<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Yet another blog</title>
  
  <subtitle>here goes the subtitle</subtitle>
  <link href="/atom.xml" rel="self"/>
  
  <link href="http://justincalleja.com/"/>
  <updated>2020-04-07T09:25:01.192Z</updated>
  <id>http://justincalleja.com/</id>
  
  <author>
    <name>Justin Calleja</name>
    
  </author>
  
  <generator uri="http://hexo.io/">Hexo</generator>
  
  <entry>
    <title>Generate your own types in fast-check</title>
    <link href="http://justincalleja.com/2020/04/07/generate-your-own-types-in-fast-check/"/>
    <id>http://justincalleja.com/2020/04/07/generate-your-own-types-in-fast-check/</id>
    <published>2020-04-07T00:00:00.000Z</published>
    <updated>2020-04-07T09:25:01.192Z</updated>
    
    <content type="html"><![CDATA[<h3 id="TLDR"><a href="#TLDR" class="headerlink" title="TLDR"></a>TLDR</h3><p>If your custom type is:</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> ImaCustom &#123;</span><br><span class="line">    <span class="constructor"><span class="keyword">constructor</span>(public s: Set&lt;string&gt;, public a: string[]) </span>&#123;&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>… and if you’re just getting started with this (like me) and thinking: “ok, now how do I randomly generate my <code>ImaCustom</code> instances?”.</p><p>Try generating random sets and arrays which you can then use to create your <code>ImaCustom</code>s.</p><p>e.g.</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> fc from <span class="string">"fast-check"</span>;</span><br><span class="line"></span><br><span class="line">test(<span class="string">"Some property you want to test"</span>, () =&gt; &#123;</span><br><span class="line">  fc.assert(</span><br><span class="line">    fc.property(</span><br><span class="line">      <span class="comment">// generate [Set&lt;string&gt;, string[]] tuples with some size constraints</span></span><br><span class="line">      fc.tuple(fc.set(fc.string(<span class="number">100</span>), <span class="number">25</span>), fc.array(fc.string(<span class="number">100</span>), <span class="number">50</span>)),</span><br><span class="line">      ([s, a]) =&gt; &#123;</span><br><span class="line">        <span class="keyword">const</span> i = <span class="keyword">new</span> ImaCustom(s, a);</span><br><span class="line">        <span class="comment">// assert your property</span></span><br><span class="line">      &#125;</span><br><span class="line">    )</span><br><span class="line">  );</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>That’s basically what I wanted to write about 😊</p><h3 id="A-slow-start-to-a-fast-check"><a href="#A-slow-start-to-a-fast-check" class="headerlink" title="A slow start to a fast-check"></a>A slow start to a fast-check</h3><p>I guess you already know what property based testing is if you’re here. Recently, I was testing something… which tbh, I didn’t really know how I wanted to work. But in my mind, I could think of certain properties; certain things which had to hold on the datastructure in question when this operation happens. So - I figured I’d reach for that testing approach I know about; think is amazing; but almost never actually use 🤔</p><p>Anyway - it didn’t take long to find <a href="https://github.com/dubzzz/fast-check#readme" target="_blank" rel="external">fast-check</a>. I had used <a href="https://github.com/jsverify/jsverify" target="_blank" rel="external">jsverify</a> before, but I’ve forgotten the API and who cares anyway - I just want to code a few properties and get on with my app… maybe actually get it to a usable state 😅</p><p>So… I’m searching online:</p><blockquote><p>Ye, I know more or less what property based testing is. Great - first few examples show how to generate basic types. Cool, found the list of built-in… oh “arbitraries” they’re called… hmm fancy that - and I thought I had an arbitrary name. Now if I could only get to the “how to generate your own flippin’ types” in the documentation and give these stressed eyeballs a break.</p></blockquote><p>Far as I can tell - that section doesn’t exist in the docs. I did eventually have a 🤦‍♂️ moment and realised that any “custom” datastructure must be made up of more basic types.</p><h3 id="Show-me-da-code"><a href="#Show-me-da-code" class="headerlink" title="Show me da code!"></a>Show me da code!</h3><p>This is basically the data I’m working with here (<a href="https://immutable-js.github.io/immutable-js/docs/#/" target="_blank" rel="external">Immutable.js</a> Set / OrderedSet):</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="interface"><span class="keyword">interface</span> ContentProps </span>&#123;</span><br><span class="line">  include?: OrderedSet&lt;<span class="built_in">string</span>&gt;;</span><br><span class="line">  exclude?: Set&lt;<span class="built_in">string</span>&gt;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>… which is passed in to <code>Content</code>‘s constructor to create an instance. But the constructor has some constraints:</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (include.has(<span class="string">""</span>) || exclude.has(<span class="string">""</span>)) &#123;</span><br><span class="line"><span class="comment">// ... throw Error</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> invalidValues = include.intersect(exclude);</span><br><span class="line"><span class="keyword">if</span> (invalidValues.size &gt; <span class="number">0</span>) &#123;</span><br><span class="line"><span class="comment">// ... throw Error</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>So basically, no empty string in the sets and they must be mutually exclusive.</p><p>Finally, a <code>Content</code> can <code>sync</code> given a list of file paths <code>string[]</code>… and this is what I came up with for what I had in mind. <strong>NOTE:</strong> you do not need to understand or even read this code:</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> sync(filePaths: <span class="built_in">string</span>[] = []): Content &#123;</span><br><span class="line">  <span class="keyword">const</span> filePathsAsSet = Set(filePaths);</span><br><span class="line">  <span class="keyword">const</span> setOfFilePathsNotAlreadyExcluded = filePathsAsSet.subtract(</span><br><span class="line">    <span class="keyword">this</span>.exclude</span><br><span class="line">  );</span><br><span class="line">  <span class="keyword">const</span> oldValidSectionsInRightOrder = <span class="keyword">this</span>.include.intersect(</span><br><span class="line">    setOfFilePathsNotAlreadyExcluded</span><br><span class="line">  );</span><br><span class="line">  <span class="keyword">const</span> newValidSections = setOfFilePathsNotAlreadyExcluded.subtract(</span><br><span class="line">    oldValidSectionsInRightOrder</span><br><span class="line">  );</span><br><span class="line"></span><br><span class="line">  <span class="keyword">const</span> include = oldValidSectionsInRightOrder.concat(newValidSections);</span><br><span class="line">  <span class="keyword">const</span> exclude = filePathsAsSet.intersect(<span class="keyword">this</span>.exclude);</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">new</span> Content(&#123;</span><br><span class="line">    dirName: <span class="keyword">this</span>.dirName,</span><br><span class="line">    include,</span><br><span class="line">    exclude</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>One property I can think of is this:</p><blockquote><p>In <code>result = content.sync(filePaths: string[])</code> - any filePath in <code>filePaths</code> which is also in <code>content.exclude</code> should be in <code>result.exclude</code> and not in <code>result.include</code></p></blockquote><p>This is the property being demoed below, but if you want to get a feel of what <code>sync</code> is about, here are a couple more properties which come to mind:</p><ul><li>Any existing values in <code>content.exclude</code> which are not present in <code>filePaths</code> should not be in <code>result.exclude</code></li><li>Any existing values in <code>content.include</code> which are not present in <code>filePaths</code> should not be in <code>result.include</code></li><li>Any existing values in <code>content.include</code> which are in <code>filePaths</code> are kept in the same order in <code>result.include</code></li></ul><h3 id="Generating-data"><a href="#Generating-data" class="headerlink" title="Generating data"></a>Generating data</h3><p>To express this property, I first want to express how the “ingredients” are generated, i.e. the arbitrary data:</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> arbitrarySyncTestProps = fc.tuple(</span><br><span class="line">  fc.set(fc.string(<span class="number">100</span>), <span class="number">25</span>),</span><br><span class="line">  fc.set(fc.string(<span class="number">100</span>), <span class="number">25</span>),</span><br><span class="line">  fc.array(fc.string(<span class="number">100</span>), <span class="number">50</span>)</span><br><span class="line">);</span><br></pre></td></tr></table></figure><p>So - generate me a tuple of 2 sets of strings with a max size of 25 and whose strings are no more than 100 characters in length. Also, throw in an array of strings for good measure. Super simple - but now I want to get more specific… I should have no empty strings in either Set, nor in the array come to think of it - as those elements are meant to end up in a Set which doesn’t want empty strings. Also, I want the two Sets to be mutually exclusive… and while we’re at it - I think it won’t do to just have random strings. Taking another look at the property:</p><blockquote><p>any filePath in <code>filePaths</code> which is also in <code>content.exclude</code> </p></blockquote><p>So, maybe I should ensure I get some strings which are in both <code>filePaths</code> and <code>exclude</code>:</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> arbitrarySyncTestProps = fc</span><br><span class="line">  .tuple(</span><br><span class="line">    fc.set(fc.string(<span class="number">100</span>), <span class="number">25</span>),</span><br><span class="line">    fc.set(fc.string(<span class="number">100</span>), <span class="number">25</span>),</span><br><span class="line">    fc.array(fc.string(<span class="number">100</span>), <span class="number">50</span>)</span><br><span class="line">  )</span><br><span class="line">  .map(([include, exclude, filePaths]) =&gt; &#123;</span><br><span class="line">    <span class="comment">// make filePathsToAddToExclude so tests can be more meaningful</span></span><br><span class="line">    <span class="keyword">let</span> filePathsToAddToExclude = [];</span><br><span class="line">    <span class="keyword">if</span> (filePaths.length &gt; <span class="number">0</span>) &#123;</span><br><span class="line">      <span class="keyword">const</span> numberOfPathsToAddToExclude = <span class="built_in">Math</span>.floor(</span><br><span class="line">        <span class="built_in">Math</span>.random() * filePaths.length</span><br><span class="line">      );</span><br><span class="line">      <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt;= numberOfPathsToAddToExclude; i++) &#123;</span><br><span class="line">        filePathsToAddToExclude.push(filePaths[i]);</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// transform the data so it meets Content's pre-conditions</span></span><br><span class="line">    <span class="keyword">const</span> includeOrderedSet = OrderedSet(</span><br><span class="line">      include.filter((x) =&gt; x !== <span class="string">""</span> &amp;&amp; !exclude.includes(x))</span><br><span class="line">    );</span><br><span class="line">    <span class="keyword">const</span> excludeSet = Set(</span><br><span class="line">      exclude.concat(filePathsToAddToExclude).filter((x) =&gt; x !== <span class="string">""</span>)</span><br><span class="line">    );</span><br><span class="line">    <span class="keyword">const</span> filePathsArray = filePaths.filter((x) =&gt; x !== <span class="string">""</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> [includeOrderedSet, excludeSet, filePathsArray];</span><br><span class="line">  &#125;);</span><br></pre></td></tr></table></figure><h3 id="Expressing-the-property"><a href="#Expressing-the-property" class="headerlink" title="Expressing the property"></a>Expressing the property</h3><p>Finally, the property can be expressed with a few simple assertions:</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">([include, exclude, filePaths]: [</span><br><span class="line">  OrderedSet&lt;<span class="built_in">string</span>&gt;,</span><br><span class="line">  Set&lt;<span class="built_in">string</span>&gt;,</span><br><span class="line">  <span class="built_in">string</span>[]</span><br><span class="line">]) =&gt; &#123;</span><br><span class="line">  <span class="keyword">const</span> content = <span class="keyword">new</span> Content(&#123;</span><br><span class="line">    include,</span><br><span class="line">    exclude,</span><br><span class="line">  &#125;);</span><br><span class="line">  <span class="keyword">const</span> result = content.sync(filePaths);</span><br><span class="line">  <span class="keyword">const</span> pathsInBothFilePathsAndExclude: Set&lt;<span class="built_in">string</span>&gt; = content.exclude.intersect(</span><br><span class="line">    Set(filePaths)</span><br><span class="line">  );</span><br><span class="line"></span><br><span class="line">  expect(pathsInBothFilePathsAndExclude.isSubset(content.exclude)).toBe(<span class="literal">true</span>);</span><br><span class="line">  expect(result.include.intersect(pathsInBothFilePathsAndExclude).size).toBe(<span class="number">0</span>);</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h4 id="Putting-it-all-together"><a href="#Putting-it-all-together" class="headerlink" title="Putting it all together"></a>Putting it all together</h4><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> fc from <span class="string">"fast-check"</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; Set, OrderedSet &#125; from <span class="string">"immutable"</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; Content &#125; from <span class="string">"./Content"</span>;</span><br><span class="line"></span><br><span class="line">describe(<span class="string">"Content"</span>, () =&gt; &#123;</span><br><span class="line">  describe(<span class="string">"content.sync(filePaths: string[])"</span>, () =&gt; &#123;</span><br><span class="line">    test(<span class="string">"Any filePath in filePaths which is also in content.exclude should be in result.exclude and not in result.include"</span>, () =&gt; &#123;</span><br><span class="line">      <span class="keyword">const</span> arbitrarySyncTestProps = fc</span><br><span class="line">        .tuple(</span><br><span class="line">          fc.set(fc.string(<span class="number">100</span>), <span class="number">25</span>),</span><br><span class="line">          fc.set(fc.string(<span class="number">100</span>), <span class="number">25</span>),</span><br><span class="line">          fc.array(fc.string(<span class="number">100</span>), <span class="number">50</span>)</span><br><span class="line">        )</span><br><span class="line">        .map(([include, exclude, filePaths]) =&gt; &#123;</span><br><span class="line">          <span class="comment">// make filePathsToAddToExclude so tests can be more meaningful</span></span><br><span class="line">          <span class="keyword">let</span> filePathsToAddToExclude = [];</span><br><span class="line">          <span class="keyword">if</span> (filePaths.length &gt; <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="keyword">const</span> numberOfPathsToAddToExclude = <span class="built_in">Math</span>.floor(</span><br><span class="line">              <span class="built_in">Math</span>.random() * filePaths.length</span><br><span class="line">            );</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt;= numberOfPathsToAddToExclude; i++) &#123;</span><br><span class="line">              filePathsToAddToExclude.push(filePaths[i]);</span><br><span class="line">            &#125;</span><br><span class="line">          &#125;</span><br><span class="line"></span><br><span class="line">          <span class="comment">// transform the data so it meets Content's pre-conditions</span></span><br><span class="line">          <span class="keyword">const</span> includeOrderedSet = OrderedSet(</span><br><span class="line">            include.filter((x) =&gt; x !== <span class="string">""</span> &amp;&amp; !exclude.includes(x))</span><br><span class="line">          );</span><br><span class="line">          <span class="keyword">const</span> excludeSet = Set(</span><br><span class="line">            exclude.concat(filePathsToAddToExclude).filter((x) =&gt; x !== <span class="string">""</span>)</span><br><span class="line">          );</span><br><span class="line">          <span class="keyword">const</span> filePathsArray = filePaths.filter((x) =&gt; x !== <span class="string">""</span>);</span><br><span class="line"></span><br><span class="line">          <span class="keyword">return</span> [includeOrderedSet, excludeSet, filePathsArray];</span><br><span class="line">        &#125;);</span><br><span class="line"></span><br><span class="line">      fc.assert(</span><br><span class="line">        fc.property(</span><br><span class="line">          arbitrarySyncTestProps,</span><br><span class="line">          ([include, exclude, filePaths]: [</span><br><span class="line">            OrderedSet&lt;<span class="built_in">string</span>&gt;,</span><br><span class="line">            Set&lt;<span class="built_in">string</span>&gt;,</span><br><span class="line">            <span class="built_in">string</span>[]</span><br><span class="line">          ]) =&gt; &#123;</span><br><span class="line">            <span class="keyword">const</span> content = <span class="keyword">new</span> Content(&#123;</span><br><span class="line">              include,</span><br><span class="line">              exclude,</span><br><span class="line">            &#125;);</span><br><span class="line">            <span class="keyword">const</span> result = content.sync(filePaths);</span><br><span class="line">            <span class="keyword">const</span> pathsInBothFilePathsAndExclude: Set&lt;<span class="built_in">string</span>&gt; = content.exclude.intersect(</span><br><span class="line">              Set(filePaths)</span><br><span class="line">            );</span><br><span class="line"></span><br><span class="line">            expect(</span><br><span class="line">              pathsInBothFilePathsAndExclude.isSubset(content.exclude)</span><br><span class="line">            ).toBe(<span class="literal">true</span>);</span><br><span class="line">            expect(</span><br><span class="line">              result.include.intersect(pathsInBothFilePathsAndExclude).size</span><br><span class="line">            ).toBe(<span class="number">0</span>);</span><br><span class="line">          &#125;</span><br><span class="line">        )</span><br><span class="line">      );</span><br><span class="line">    &#125;);</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h3 id="In-conclusion"><a href="#In-conclusion" class="headerlink" title="In conclusion"></a>In conclusion</h3><p>It was fun to revisit property based testing. One issue I know will come up is the matter of performance. This is taking circa <em>5 seconds</em> to run so I know its going to be problem. Maybe I’ll only run the property based tests when an env var is set, or configure <code>fast-check</code> to “be more fast!” … somehow (e.g. generate less tests). In any case, it’s still useful and I have already found a couple of issues with my implementation.</p><p>Any feedback on this is more than welcome 👇</p><p>🍻</p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h3 id=&quot;TLDR&quot;&gt;&lt;a href=&quot;#TLDR&quot; class=&quot;headerlink&quot; title=&quot;TLDR&quot;&gt;&lt;/a&gt;TLDR&lt;/h3&gt;&lt;p&gt;If your custom type is:&lt;/p&gt;
&lt;figure class=&quot;highlight ts&quot;&gt;&lt;tabl
      
    
    </summary>
    
      <category term="programming" scheme="http://justincalleja.com/categories/programming/"/>
    
    
      <category term="fast-check" scheme="http://justincalleja.com/tags/fast-check/"/>
    
      <category term="property based testing" scheme="http://justincalleja.com/tags/property-based-testing/"/>
    
  </entry>
  
  <entry>
    <title>Using plain pg with Nest.js</title>
    <link href="http://justincalleja.com/2020/03/26/using-plain-pg-with-nestjs/"/>
    <id>http://justincalleja.com/2020/03/26/using-plain-pg-with-nestjs/</id>
    <published>2020-03-26T13:19:25.000Z</published>
    <updated>2020-04-07T09:25:01.205Z</updated>
    
    <content type="html"><![CDATA[<h2 id="Intro"><a href="#Intro" class="headerlink" title="Intro"></a>Intro</h2><p>This is going to be a quick demo of how to get started using plain <a href="https://node-postgres.com/" target="_blank" rel="external">pg (node-postgres)</a> with <a href="https://nestjs.com/" target="_blank" rel="external">Nest.js</a> — no ORMs in sight. Having found no simple guide on how to do this when I was looking for it — I figured it’d be worth writing about.</p><h2 id="Demo-on-Github"><a href="#Demo-on-Github" class="headerlink" title="Demo on Github:"></a>Demo on Github:</h2><p><a href="https://github.com/justin-calleja/nest-pg-demo" target="_blank" rel="external">https://github.com/justin-calleja/nest-pg-demo</a></p><h2 id="Using-plain-pg-with-Nest-js"><a href="#Using-plain-pg-with-Nest-js" class="headerlink" title="Using plain pg with Nest.js"></a>Using plain pg with Nest.js</h2><h3 id="Create-a-new-Nest-js-app-—-install-pg-—-generate-db-module"><a href="#Create-a-new-Nest-js-app-—-install-pg-—-generate-db-module" class="headerlink" title="Create a new Nest.js app — install pg — generate db module"></a>Create a new Nest.js app — install pg — generate db module</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">npx nest new nest-pg-demo</span><br><span class="line"><span class="built_in">cd</span> nest-pg-demo</span><br><span class="line">npm i pg</span><br><span class="line">npx nest g module db</span><br></pre></td></tr></table></figure><h3 id="Register-a-Provider"><a href="#Register-a-Provider" class="headerlink" title="Register a Provider"></a>Register a Provider</h3><p>We’ll use a constants.ts file in /src to be able to import the DI token for our postgres connection (or pool of connections):</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// src/constants.ts</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> PG_CONNECTION = <span class="string">'PG_CONNECTION'</span>;</span><br></pre></td></tr></table></figure><p>The DI token (dependency injection token) is how you’ll declaratively tell the <a href="https://en.wikipedia.org/wiki/Inversion_of_control" target="_blank" rel="external">Inversion of Control (IoC)</a> container which dependency you’d like injected. So you’ll use it to pull in a dependency from the container.</p><p>You’ll also use it when you register a provider with the container. Registering a provider is basically associating a DI token (which will be a string in our case) with a way to get a dependency. The container will use this “way to get a dependency” when you request the relevant dependency be injected.</p><p>Registering a provider looks like this:</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; Module &#125; from <span class="string">'@nestjs/common'</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; PG_CONNECTION &#125; from <span class="string">'../constants'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> dbProvider = &#123;</span><br><span class="line">    provide: PG_CONNECTION,</span><br><span class="line">    <span class="comment">// useValue / useFacotry / useClass: …</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">@Module(&#123;</span><br><span class="line">    providers: [dbProvider],</span><br><span class="line">&#125;)</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> DbModule &#123;&#125;</span><br></pre></td></tr></table></figure><p>i.e. we need an object with the DI token and the way to get the dependency — the dbProvider — and pass it to <strong>providers</strong> in the Module configuration as shown above.</p><p>There’s a couple of ways to specify how to get the dependency in Nest.js. We’ll be using <a href="https://docs.nestjs.com/fundamentals/custom-providers#value-providers-usevalue" target="_blank" rel="external">useValue</a>:</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; Pool &#125; from <span class="string">'pg'</span>;</span><br><span class="line"><span class="keyword">const</span> dbProvider = &#123;</span><br><span class="line">  provide: PG_CONNECTION,</span><br><span class="line">  useValue: <span class="keyword">new</span> Pool(&#123;</span><br><span class="line">    user: <span class="string">'postgres'</span>,</span><br><span class="line">    host: <span class="string">'localhost'</span>,</span><br><span class="line">    database: <span class="string">'somedb'</span>,</span><br><span class="line">    password: <span class="string">'meh'</span>,</span><br><span class="line">    port: <span class="number">5432</span>,</span><br><span class="line">  &#125;),</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>Finally, we’ll also include the dbProvider in the DbModule’s exports so we’ll be able to use it in other modules importing <code>DbModule</code>:</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; Module &#125; from <span class="string">'@nestjs/common'</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; Pool &#125; from <span class="string">'pg'</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; PG_CONNECTION &#125; from <span class="string">'../constants'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> dbProvider = &#123;</span><br><span class="line">    provide: PG_CONNECTION,</span><br><span class="line">    useValue: <span class="keyword">new</span> Pool(&#123;</span><br><span class="line">        user: <span class="string">'postgres'</span>,</span><br><span class="line">        host: <span class="string">'localhost'</span>,</span><br><span class="line">        database: <span class="string">'somedb'</span>,</span><br><span class="line">        password: <span class="string">'meh'</span>,</span><br><span class="line">        port: <span class="number">5432</span>,</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">@Module(&#123;</span><br><span class="line">    providers: [dbProvider],</span><br><span class="line">    exports: [dbProvider],</span><br><span class="line">&#125;)</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> DbModule &#123;&#125;</span><br></pre></td></tr></table></figure><h3 id="Use-the-Provider"><a href="#Use-the-Provider" class="headerlink" title="Use the Provider"></a>Use the Provider</h3><p>You’ll notice that the <code>AppModule</code> is already importing <code>DbModule</code> (at least if you generated DbModule with the <code>nest cli</code> that should be the case):</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// src/app.module.ts</span></span><br><span class="line"><span class="keyword">import</span> &#123; Module &#125; from <span class="string">'@nestjs/common'</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; AppController &#125; from <span class="string">'./app.controller'</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; AppService &#125; from <span class="string">'./app.service'</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; DbModule &#125; from <span class="string">'./db/db.module'</span>;</span><br><span class="line"></span><br><span class="line">@Module(&#123;</span><br><span class="line">  imports: [DbModule],</span><br><span class="line">  controllers: [AppController],</span><br><span class="line">  providers: [AppService],</span><br><span class="line">&#125;)</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> AppModule &#123;&#125;</span><br></pre></td></tr></table></figure><p>This means that — in our AppModule i.e. in e.g. controllers and providers defined as part of AppModule) we’ll be able to ask Nest’s IoC container to inject a connection for us using the <code>PG_CONNECTION</code> DI token (string).</p><p>Doing so in our <code>AppService</code> looks something like this:</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// src/app.service.ts</span></span><br><span class="line"><span class="keyword">import</span> &#123; Injectable, Inject &#125; from <span class="string">'@nestjs/common'</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; PG_CONNECTION &#125; from <span class="string">'./constants'</span>;</span><br><span class="line"></span><br><span class="line">@Injectable()</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> AppService &#123;</span><br><span class="line">  <span class="constructor"><span class="keyword">constructor</span>(@Inject(PG_CONNECTION) private conn: any) </span>&#123;&#125;</span><br><span class="line"></span><br><span class="line">  async getUsers() &#123;</span><br><span class="line">    <span class="keyword">const</span> res = await <span class="keyword">this</span>.conn.query(<span class="string">'SELECT * FROM users'</span>);</span><br><span class="line">    <span class="keyword">return</span> res.rows;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Notice that we annotate <code>conn</code> with <code>Inject</code> and make it private in the <code>constructor</code>. This is significant at it allows Nest to know that <em>it</em> should be the one to supply a value for <code>conn</code> and it also knows what to inject via the DI token.</p><p><code>getUsers</code> is just a simple query to use as a sanity check. We’ll use it in <code>AppController</code>:</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// src/app.controller.ts</span></span><br><span class="line"><span class="keyword">import</span> &#123; Controller, Get &#125; from <span class="string">'@nestjs/common'</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; AppService &#125; from <span class="string">'./app.service'</span>;</span><br><span class="line"></span><br><span class="line">@Controller()</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> AppController &#123;</span><br><span class="line">  <span class="constructor"><span class="keyword">constructor</span>(private readonly appService: AppService) </span>&#123;&#125;</span><br><span class="line"></span><br><span class="line">  @Get(<span class="string">'users'</span>)</span><br><span class="line">  getUsers() &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">this</span>.appService.getUsers();</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>I guess you might be wondering how we’re able to inject <code>AppService</code> here without the <code>Inject</code> annotation… That’s thanks to a shortcut (or “syntactic sugar” if you prefer). In Nest.js, registering a Provider with a class name:</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; AppService &#125; from <span class="string">'./app.service'</span>;</span><br><span class="line">@Module(&#123;</span><br><span class="line">  providers: [AppService],</span><br><span class="line">&#125;)</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> AppModule &#123;&#125;</span><br></pre></td></tr></table></figure><p>… is equivalent to:</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; AppService &#125; from <span class="string">'./app.service'</span>;</span><br><span class="line">@Module(&#123;</span><br><span class="line">  providers: [&#123;</span><br><span class="line">    provider: AppService,</span><br><span class="line">    useClass: AppService,</span><br><span class="line">  &#125;],</span><br><span class="line">&#125;)</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> AppModule &#123;&#125;</span><br></pre></td></tr></table></figure><p>… which means — the DI token doesn’t have to be a string and now Nest.js knows what to inject when we type the <code>private appService</code> in <code>AppController</code> with the type <code>AppService</code>.</p><h3 id="Start-and-seed-postgres"><a href="#Start-and-seed-postgres" class="headerlink" title="Start and seed postgres"></a>Start and seed postgres</h3><p>Of course, you’re going to want postgres running if you want to try this out. If you have docker installed, take a look at the <code>scripts</code> and <code>sql</code> directories in the <a href="https://github.com/justin-calleja/nest-pg-demo" target="_blank" rel="external">repo</a> for this demo — but the gist is:</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="shebang">#!/bin/bash</span></span><br><span class="line">docker run --rm \</span><br><span class="line">    --name somedb \</span><br><span class="line">    <span class="operator">-e</span> POSTGRES_PASSWORD=meh \</span><br><span class="line">    <span class="operator">-e</span> POSTGRES_USER=postgres \</span><br><span class="line">    <span class="operator">-e</span> POSTGRES_DB=somedb \</span><br><span class="line">    -p <span class="number">5432</span>:<span class="number">5432</span> \</span><br><span class="line">    -v somedb-vol:/var/lib/postgresql/data \</span><br><span class="line">    postgres</span><br></pre></td></tr></table></figure><p><code>scripts/start-db.sh</code> starts postgres. <code>--rm</code> will remove the container when we stop it. By virtue of passing in the env vars we do — the container will auto create the somedb database. The volume mapping is so we keep our data even when we stop the container (and have it auto-removed).</p><p>After the db is up — you can run <code>scripts/sync-db.sh</code>:</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="shebang">#!/bin/bash</span></span><br><span class="line">SCRIPTS_DIR=`dirname <span class="string">"<span class="variable">$0</span>"</span>`</span><br><span class="line">cat <span class="string">"<span class="variable">$SCRIPTS_DIR</span>/../sql/schema.sql"</span> <span class="string">"<span class="variable">$SCRIPTS_DIR</span>/../sql/dev-seeds.sql"</span> \</span><br><span class="line">    | psql -U postgres <span class="operator">-d</span> somedb -p <span class="number">5432</span> -h localhost -<span class="number">1</span> <span class="operator">-f</span> -</span><br></pre></td></tr></table></figure><p>This should work regardless of your <code>pwd</code> when you run the script since we’re referencing the sql files relative to the location of the <code>sync-db.sh</code> file on disk (consider this to be an equivalent of <code>__dirname</code> in Node.js). Since <code>schema.sql</code> drops and re-creates the public schema every time — it’s safe to re-run <code>sync-db.sh</code> when you change your table definitions etc…</p><h3 id="Start-the-app-and-GET-users"><a href="#Start-the-app-and-GET-users" class="headerlink" title="Start the app and GET /users"></a>Start the app and GET /users</h3><p>Finally, it’s time to run our app with <code>npm run start:dev</code> and hit the <code>/users</code> endpoint with:</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">curl localhost:<span class="number">3000</span>/users</span><br><span class="line">[&#123;<span class="string">"id"</span>:<span class="number">1</span>,<span class="string">"email"</span>:<span class="string">"tmp@gmail.com"</span>&#125;,&#123;<span class="string">"id"</span>:<span class="number">2</span>,<span class="string">"email"</span>:<span class="string">"user@gmail.com"</span>&#125;,&#123;<span class="string">"id"</span>:<span class="number">3</span>,<span class="string">"email"</span>:<span class="string">"anotheruser@gmail.com"</span>&#125;]</span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h2 id=&quot;Intro&quot;&gt;&lt;a href=&quot;#Intro&quot; class=&quot;headerlink&quot; title=&quot;Intro&quot;&gt;&lt;/a&gt;Intro&lt;/h2&gt;&lt;p&gt;This is going to be a quick demo of how to get started usi
      
    
    </summary>
    
      <category term="programming" scheme="http://justincalleja.com/categories/programming/"/>
    
    
      <category term="nestjs" scheme="http://justincalleja.com/tags/nestjs/"/>
    
      <category term="node" scheme="http://justincalleja.com/tags/node/"/>
    
      <category term="pg" scheme="http://justincalleja.com/tags/pg/"/>
    
  </entry>
  
  <entry>
    <title>Trying out Typescript</title>
    <link href="http://justincalleja.com/2016/05/28/trying-out-typescript/"/>
    <id>http://justincalleja.com/2016/05/28/trying-out-typescript/</id>
    <published>2016-05-28T00:00:00.000Z</published>
    <updated>2020-04-07T09:25:01.202Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Intro"><a href="#Intro" class="headerlink" title="Intro"></a>Intro</h1><p>The intention was to write some demo code to see what problems I come across while just starting to use <a href="https://www.typescriptlang.org/" target="_blank" rel="external">Typescript</a>, and to document the “work-arounds” along the way. This is a suitable read for anyone who knows what Typescript is, is interested in it, but hasn’t really used it before. You should have <a href="http://redis.io/" target="_blank" rel="external">Redis</a> installed (as well as Node and Typescript) to follow along.</p><p>I’m using the <a href="https://atom.io/" target="_blank" rel="external">Atom</a> text editor with the <a href="https://github.com/TypeStrong/atom-typescript" target="_blank" rel="external">atom-typescript</a> package.</p><p>A repo for the code in this post is up on <a href="https://github.com/justin-calleja/redis-ts-eg" target="_blank" rel="external">Github</a>. Use <code>npm install &amp;&amp; typings install</code> to get started.</p><h1 id="The-demo"><a href="#The-demo" class="headerlink" title="The demo"></a>The demo</h1><p>We’re going to have 2 scripts to run, <code>pub.js</code> and <code>sub.js</code>. <code>pub.js</code> will just start up a Node <a href="https://nodejs.org/api/repl.html" target="_blank" rel="external">REPL</a> exposing a <code>redisClient</code> which we can use to publish messages on channels with. <code>sub.js</code> will be subscribing to channels and listening to messages published by <code>pub.js</code>.</p><p>Below is a quick session for illustration:</p><p><img src="pub.png" alt="pub.js" title="pub.js"></p><p><img src="sub.png" alt="sub.js" title="sub.js"></p><p>Simple, but making the compiler happy took a bit of fiddling.</p><h1 id="pub-ts"><a href="#pub-ts" class="headerlink" title="pub.ts"></a>pub.ts</h1><h2 id="tsconfig-json"><a href="#tsconfig-json" class="headerlink" title="tsconfig.json"></a>tsconfig.json</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">$ mkdir redis-ts-eg &amp;&amp; <span class="built_in">cd</span> redis-ts-eg</span><br><span class="line">redis-ts-eg$ npm init --yes</span><br><span class="line">redis-ts-eg$ npm i -S redis</span><br><span class="line">redis-ts-eg$ mkdir src lib</span><br></pre></td></tr></table></figure><p>If you now open <code>redis-ts-eg</code> in Atom and create <code>pub.ts</code> (note the <code>ts</code> extension) in <code>src</code>, you should get the following error (and suggestion):</p><p><img src="missing-tsconfig.png" alt="missing-tsconfig" title="missing-tsconfig"></p><p>We’re missing a <a href="https://www.typescriptlang.org/docs/handbook/tsconfig-json.html" target="_blank" rel="external">tsconfig.json</a> <a href="https://github.com/TypeStrong/atom-typescript/blob/master/docs/tsconfig.md" target="_blank" rel="external">file</a> and we can get <a href="https://github.com/TypeStrong/atom-typescript" target="_blank" rel="external">atom-typescript</a> to create one for us using the Atom <a href="https://atom.io/packages/command-palette" target="_blank" rel="external">command-palette</a> by hitting <code>cmd-shift-p</code> (OSX) or <code>ctrl-shift-p</code> (Linux/Windows).</p><p>Once you have that open, start typing “create tsconfig.json” and you should get the option to select. This creates the file in <code>src</code>, so just move it one directory up to the project root.</p><p>So what is <code>tsconfig.json</code> anyway?</p><blockquote>A unified project format for TypeScript… The TypeScript compiler (1.5 and above) only cares about <em>compilerOptions</em> and <em>files</em><footer><cite><a href="https://github.com/TypeStrong/atom-typescript/blob/master/docs/tsconfig.md#tsconfigjson" target="_blank" rel="external">tsconfig.json atom-typescript doc</a></cite></footer></blockquote><p>Ok, so <a href="https://www.typescriptlang.org/docs/handbook/compiler-options.html" target="_blank" rel="external">compilerOptions</a> and <em>files</em> are passed to the Typescript compiler, but this isn’t to say that <code>tsconfig.json</code> is an <a href="https://github.com/TypeStrong/atom-typescript" target="_blank" rel="external">atom-typescript</a> only thing:</p><blockquote><br>Using tsconfig.json:<br><br><ul><li>By invoking tsc with no input files, in which case the compiler searches for the tsconfig.json file starting in the current directory and continuing up the parent directory chain.</li><li>By invoking tsc with no input files and a –project (or just -p) command line option that specifies the path of a directory containing a tsconfig.json file.</li></ul>When input files are specified on the command line, tsconfig.json files are ignored.<br><footer><cite><a href="https://www.typescriptlang.org/docs/handbook/tsconfig-json.html" target="_blank" rel="external">tsconfig.json Typescript doc</a></cite></footer></blockquote><p>i.e. both Typescript and atom-typescript use the file (the teams behind each collaborate to avoid conflicts). </p><p>In <code>tsconfig.json</code>, <a href="https://github.com/TypeStrong/atom-typescript/blob/master/docs/tsconfig.md#filesglob" target="_blank" rel="external">filesGlob</a> is a field used by atom-typescript to keep <code>files</code> up to date. i.e. any files matched by <code>filesGlob</code> are automatically (and individually) listed by Atom in <code>files</code> (which <em>is</em> used by <code>tsc</code>, the Typescript compiler).</p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">"filesGlob": [</span><br><span class="line">    "**/*.ts",</span><br><span class="line">    "**/*.tsx",</span><br><span class="line">    "!node_modules/**"</span><br><span class="line">],</span><br></pre></td></tr></table></figure><h2 id="typings"><a href="#typings" class="headerlink" title="typings"></a>typings</h2><p>Great, so I guess we’re ready to start coding now:</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> redis = <span class="built_in">require</span>(<span class="string">'redis'</span>);</span><br></pre></td></tr></table></figure><p><img src="cannot-find-redis.png" alt="Cannot find module &#39;redis&#39;"></p><p>Not so fast. We’re importing <code>redis</code> (Typescript style) but the compiler knows nothing about it. To fix this we’ll use <a href="https://github.com/typings/typings" target="_blank" rel="external">typings</a>, the Typescript Definition Manager, to fetch a description of what the <code>redis</code> module is (i.e. a <code>.d.ts</code> file).</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">redis-ts-eg$ <span class="comment"># Install Typings CLI utility if you don't already have it</span></span><br><span class="line">redis-ts-eg$ npm install typings --global</span><br><span class="line">redis-ts-eg$ typings --version</span><br><span class="line"><span class="number">1.0</span>.<span class="number">4</span></span><br><span class="line">redis-ts-eg$ typings search redis</span><br><span class="line">Viewing <span class="number">5</span> of <span class="number">5</span></span><br><span class="line"></span><br><span class="line">NAME            SOURCE HOMEPAGE                                    DESCRIPTION VERSIONS UPDATED</span><br><span class="line">node_redis      dt     https://github.com/mranney/node_redis                   <span class="number">1</span>        <span class="number">2016</span>-<span class="number">03</span>-<span class="number">16</span>T15:<span class="number">55</span>:<span class="number">26.000</span>Z</span><br><span class="line">redis           npm    https://www.npmjs.com/package/redis                     <span class="number">1</span>        <span class="number">2016</span>-<span class="number">05</span>-<span class="number">02</span>T17:<span class="number">09</span>:<span class="number">35.000</span>Z</span><br><span class="line">redis           dt     https://github.com/mranney/node_redis                   <span class="number">1</span>        <span class="number">2016</span>-<span class="number">03</span>-<span class="number">16</span>T15:<span class="number">55</span>:<span class="number">26.000</span>Z</span><br><span class="line">socket.io-redis dt     https://github.com/socketio/socket.io-redis             <span class="number">1</span>        <span class="number">2016</span>-<span class="number">04</span>-<span class="number">01</span>T04:<span class="number">54</span>:<span class="number">12.000</span>Z</span><br><span class="line">ioredis         dt     https://github.com/luin/ioredis                         <span class="number">1</span>        <span class="number">2016</span>-<span class="number">05</span>-<span class="number">21</span>T15:<span class="number">26</span>:<span class="number">53.000</span>Z</span><br></pre></td></tr></table></figure><p>You can tell typings to install from one of these <a href="https://github.com/typings/typings#sources" target="_blank" rel="external">sources</a> (assuming a type definition is available at a given source - something you can confirm through searching as done above). <code>npm</code> is the default (configurable through <code>defaultSource</code> in <code>.typingsrc</code>).</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">redis-ts-eg$ typings install redis --save</span><br></pre></td></tr></table></figure><p>After installing, you should get a <code>typings.json</code> file and a <code>typings</code> directory. If you save <code>tsconfig.json</code> now, it should update <code>files</code> to:</p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">"files": [</span><br><span class="line">    "src/pub.ts",</span><br><span class="line">    "typings/index.d.ts",</span><br><span class="line">    "typings/modules/redis/index.d.ts"</span><br><span class="line">],</span><br></pre></td></tr></table></figure><p>It would work just as well without <code>typings/modules/redis/index.d.ts</code> as <code>typings/index.d.ts</code> references it. In any case, the “Cannot find module ‘redis’” error should be gone now (try closing and re-opening the file if not).</p><p>Before continuing, notice that the compiler generates <code>src/pub.js</code> (even when we had an error - Typescript will still transpile to Javascript even with errors). To move the compiler’s output to <code>lib</code> we can add the following to <code>compilerOptions</code> in <code>tsconfig.json</code>:</p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">"compilerOptions": &#123;</span><br><span class="line">  "outDir": "lib",</span><br><span class="line">  ...</span><br></pre></td></tr></table></figure><p>Saving <code>pub.ts</code> now should generate <code>pub.js</code> in <code>lib</code>.</p><p>We can move on by importing the next module we’ll need and going through a similar process as with the <code>redis</code> module:</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> repl = <span class="built_in">require</span>(<span class="string">'repl'</span>);</span><br></pre></td></tr></table></figure><p><a href="https://nodejs.org/api/repl.html" target="_blank" rel="external">repl</a> is a module that comes with the Node distribution, but <code>tsc</code> has no knowledge of it.</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">redis-ts-eg$ typings search node</span><br><span class="line">Viewing <span class="number">20</span> of <span class="number">212</span></span><br><span class="line"></span><br><span class="line">NAME                          SOURCE HOMEPAGE                                           DESCRIPTION VERSIONS UPDATED</span><br><span class="line">analytics-node                dt     https://segment.com/docs/libraries/node/                       <span class="number">1</span>        <span class="number">2016</span>-<span class="number">03</span>-<span class="number">17</span>T12:<span class="number">06</span>:<span class="number">54.000</span>Z</span><br><span class="line">i18next-node-fs-backend       dt     https://github.com/i18next/i18next-node-fs-backend             <span class="number">1</span>        <span class="number">2016</span>-<span class="number">03</span>-<span class="number">19</span>T10:<span class="number">37</span>:<span class="number">45.000</span>Z</span><br><span class="line">i18n-node                     dt     https://github.com/mashpie/i18n-node                           <span class="number">1</span>        <span class="number">2016</span>-<span class="number">05</span>-<span class="number">21</span>T15:<span class="number">25</span>:<span class="number">45.000</span>Z</span><br><span class="line">jasmine-node                  dt     https://github.com/mhevery/jasmine-node                        <span class="number">1</span>        <span class="number">2016</span>-<span class="number">03</span>-<span class="number">16</span>T15:<span class="number">55</span>:<span class="number">26.000</span>Z</span><br><span class="line">jasmine-node-promise-matchers global                                                                <span class="number">1</span>        <span class="number">2016</span>-<span class="number">03</span>-<span class="number">10</span>T14:<span class="number">35</span>:<span class="number">55.000</span>Z</span><br><span class="line">kafka-node                    dt     https://github.com/SOHU-Co/kafka-node/                         <span class="number">1</span>        <span class="number">2016</span>-<span class="number">03</span>-<span class="number">16</span>T15:<span class="number">55</span>:<span class="number">26.000</span>Z</span><br><span class="line">mocha-node                    dt     http://mochajs.org/                                            <span class="number">1</span>        <span class="number">2016</span>-<span class="number">03</span>-<span class="number">17</span>T12:<span class="number">06</span>:<span class="number">54.000</span>Z</span><br><span class="line">moment-node                   dt     https://github.com/timrwood/moment                             <span class="number">1</span>        <span class="number">2016</span>-<span class="number">05</span>-<span class="number">11</span>T04:<span class="number">33</span>:<span class="number">38.000</span>Z</span><br><span class="line">node                          dt     http://nodejs.org/                                             <span class="number">5</span>        <span class="number">2016</span>-<span class="number">05</span>-<span class="number">23</span>T03:<span class="number">57</span>:<span class="number">54.000</span>Z</span><br><span class="line">node                          env                                                                   <span class="number">5</span>        <span class="number">2016</span>-<span class="number">05</span>-<span class="number">07</span>T21:<span class="number">03</span>:<span class="number">04.000</span>Z</span><br><span class="line">node-<span class="number">4</span>                        dt     http://nodejs.org/                                             <span class="number">1</span>        <span class="number">2016</span>-<span class="number">05</span>-<span class="number">14</span>T16:<span class="number">59</span>:<span class="number">20.000</span>Z</span><br><span class="line">node-array-ext                dt     https://github.com/Beng89/node-array-ext                       <span class="number">1</span>        <span class="number">2016</span>-<span class="number">03</span>-<span class="number">16</span>T15:<span class="number">55</span>:<span class="number">26.000</span>Z</span><br><span class="line">node-azure/azure              dt     https://github.com/WindowsAzure/azure-sdk-for-node             <span class="number">1</span>        <span class="number">2016</span>-<span class="number">03</span>-<span class="number">16</span>T15:<span class="number">55</span>:<span class="number">26.000</span>Z</span><br><span class="line">node-cache                    dt     https://github.com/tcs-de/nodecache                            <span class="number">1</span>        <span class="number">2016</span>-<span class="number">03</span>-<span class="number">17</span>T12:<span class="number">06</span>:<span class="number">54.000</span>Z</span><br><span class="line">node-calendar                 dt     https://www.npmjs.com/package/node-calendar                    <span class="number">1</span>        <span class="number">2016</span>-<span class="number">03</span>-<span class="number">16</span>T15:<span class="number">55</span>:<span class="number">26.000</span>Z</span><br><span class="line">node-config-manager           dt     https://www.npmjs.com/package/node-config-manager              <span class="number">1</span>        <span class="number">2016</span>-<span class="number">03</span>-<span class="number">16</span>T15:<span class="number">55</span>:<span class="number">26.000</span>Z</span><br><span class="line">node-dir                      dt     https://github.com/fshost/node-dir                             <span class="number">1</span>        <span class="number">2016</span>-<span class="number">03</span>-<span class="number">16</span>T15:<span class="number">55</span>:<span class="number">26.000</span>Z</span><br><span class="line">node-ffi                      dt     https://github.com/rbranson/node-ffi                           <span class="number">1</span>        <span class="number">2016</span>-<span class="number">03</span>-<span class="number">16</span>T15:<span class="number">55</span>:<span class="number">26.000</span>Z</span><br><span class="line">node-ffi/node-ffi-buffer      dt                                                                    <span class="number">1</span>        <span class="number">2014</span>-<span class="number">06</span>-<span class="number">18</span>T21:<span class="number">31</span>:<span class="number">11.000</span>Z</span><br><span class="line">node-fibers                   dt     https://github.com/laverdet/node-fibers                        <span class="number">1</span>        <span class="number">2016</span>-<span class="number">03</span>-<span class="number">17</span>T12:<span class="number">06</span>:<span class="number">54.000</span>Z</span><br></pre></td></tr></table></figure><p>After searching, you’ll see we get two options from the list above, one with a source of <code>dt</code>, and one with a source of <code>env</code>. I’ve tried installing both and they’re identical in their <code>repl</code> definitions so we’ll just pick one:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">redis-ts-eg$ typings install dt~node --save --global</span><br></pre></td></tr></table></figure><p>From what I can tell, we need to use <code>--global</code> with this one because of the contents of the definitions in its <code>.d.ts</code> (i.e. <code>typings/globals/node/index.d.ts</code>). Unlike the redis one, not everything in this <code>.d.ts</code> file is wrapped around a module declaration which exports the desired definitions. Instead, there are global definitions like these:</p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">declare var process: NodeJS.Process;</span><br><span class="line">declare var global: NodeJS.Global;</span><br><span class="line"></span><br><span class="line">declare var __filename: string;</span><br><span class="line">declare var __dirname: string;</span><br><span class="line"></span><br><span class="line">declare function setTimeout(callback: (...args: any[]) =&gt; void, ms: number, ...args: any[]): NodeJS.Timer;</span><br><span class="line">declare function clearTimeout(timeoutId: NodeJS.Timer): void;</span><br><span class="line">// etc…</span><br></pre></td></tr></table></figure><p>This is as opposed to contained (wrapped in a module) type definitions like the ones for redis which are scoped to a variable after importing the redis module.</p><p>Apparently, typings can make this distinction because it will fail to install <code>dt~node</code> without the <code>--global</code> flag.</p><p>In any case, the compiler now knows about <code>repl</code> so we can finish off <code>pub.ts</code>:</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> redis = <span class="built_in">require</span>(<span class="string">'redis'</span>);</span><br><span class="line"><span class="keyword">import</span> repl = <span class="built_in">require</span>(<span class="string">'repl'</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> redisClient = redis.createClient();</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> replServer = repl.start(&#123;</span><br><span class="line">  prompt: <span class="string">'&gt;&gt; '</span></span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">replServer.context.redisClient = redisClient;</span><br></pre></td></tr></table></figure><p>Which gives us our next challenge:</p><p><img src="context-does-not-exist.png" alt="Property &#39;context&#39; does not exist on type &#39;EventEmitter&#39;"></p><h2 id="Adding-context"><a href="#Adding-context" class="headerlink" title="Adding context"></a>Adding context</h2><p>The following is what the compiler knows about the <code>repl</code> module from <code>typings/globals/node/index.d.ts</code> (which should be automatically added to your <code>tsconfig.json</code> thanks to <code>atom-typescript</code>):</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">declare</span> <span class="module"><span class="keyword">module</span> "repl" </span>&#123;</span><br><span class="line">    <span class="keyword">import</span> * as stream from <span class="string">"stream"</span>;</span><br><span class="line">    <span class="keyword">import</span> * as events from <span class="string">"events"</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">export</span> <span class="interface"><span class="keyword">interface</span> ReplOptions </span>&#123;</span><br><span class="line">        prompt?: <span class="built_in">string</span>;</span><br><span class="line">        input?: NodeJS.ReadableStream;</span><br><span class="line">        output?: NodeJS.WritableStream;</span><br><span class="line">        terminal?: <span class="built_in">boolean</span>;</span><br><span class="line">        <span class="built_in">eval</span>?: <span class="built_in">Function</span>;</span><br><span class="line">        useColors?: <span class="built_in">boolean</span>;</span><br><span class="line">        useGlobal?: <span class="built_in">boolean</span>;</span><br><span class="line">        ignoreUndefined?: <span class="built_in">boolean</span>;</span><br><span class="line">        writer?: <span class="built_in">Function</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">export</span> <span class="function"><span class="keyword">function</span> <span class="title">start</span>(<span class="params">options: ReplOptions</span>): <span class="title">events</span>.<span class="title">EventEmitter</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>No mention of <code>context</code> anywhere. The easiest thing to do would be to add it right there. But what are we going to do in the next project which needs the same thing? Repeat the operation? Not fun.</p><p>At this point you could start managing your own <code>index.d.ts</code> for Node. Maybe submit a pull request with your changes and hope they get added. By managing your own type definitions in a repo you manage, you can import them into your code and re-use them.</p><p>However, for a throw-away project like this, I’d rather not have to stay doing this. Instead, I’ll just add a <code>typingslocal</code> directory to this project and add type definitions extending existing ones there.</p><p><strong>Note</strong>: the name is important if you want to keep <code>atom-typesript</code>‘s auto management of the <code>files</code> field in <code>tsconfig.json</code>. We want definition files under <code>typingslocal</code> to be listed <strong>below</strong> those in <code>typings</code>. That should be the case with <code>typingslocal</code> (it is for me), but if for some reason this ordering changes with whatever version of <code>atom-typescript</code> you’re using, it’s best to set <code>rewriteTsconfig</code> to <code>off</code> (in tsconfig.json) and manage <code>files</code> yourself. That way you can make sure that <code>d.ts</code> files in <code>typingslocal</code> are listed after the ones in <code>typings</code> in <code>tsconfig.json</code>‘s <code>files</code> field.</p><p>It seems to me that all we need to do in this case is define our own type extending <code>EventEmitter</code>, giving it a context and using that type for the return value of <code>start</code>:</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// typingslocal/global/node/index.d.ts</span></span><br><span class="line"><span class="keyword">declare</span> <span class="module"><span class="keyword">module</span> "repl" </span>&#123;</span><br><span class="line">  <span class="keyword">import</span> * as events from <span class="string">"events"</span>;</span><br><span class="line"></span><br><span class="line">  <span class="interface"><span class="keyword">interface</span> ReplEventEmitter <span class="keyword">extends</span> events.EventEmitter </span>&#123;</span><br><span class="line">    context: <span class="built_in">any</span>;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">export</span> <span class="function"><span class="keyword">function</span> <span class="title">start</span>(<span class="params">options: ReplOptions</span>): <span class="title">ReplEventEmitter</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>After saving <code>tsconfig.json</code>, <code>files</code> should refresh and the error in <code>pub.ts</code> should go away.</p><h1 id="sub-ts"><a href="#sub-ts" class="headerlink" title="sub.ts"></a>sub.ts</h1><p>Moving on to <code>sub.ts</code> - if you copy-paste the following, you’ll find that the compiler is only unaware of the <code>startsWith</code> method on strings:</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> redis = <span class="built_in">require</span>(<span class="string">'redis'</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> redisClient = redis.createClient();</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> defaultChannel = <span class="string">'helloChannel'</span>;</span><br><span class="line"><span class="keyword">let</span> args = process.argv.slice(<span class="number">2</span>);</span><br><span class="line"><span class="keyword">let</span> channelName: <span class="built_in">string</span> = args[<span class="number">0</span>] || defaultChannel;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">subscribe</span>(<span class="params">redisClient, channelName</span>) </span>&#123;</span><br><span class="line">  redisClient.subscribe(channelName, (err, channel) =&gt; &#123;</span><br><span class="line">    <span class="keyword">if</span> (err) <span class="keyword">throw</span> err;</span><br><span class="line">    <span class="built_in">console</span>.log(`now listening on channel: <span class="string">'$&#123;channelName&#125;'</span>`);</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">redisClient.on(<span class="string">'error'</span>, <span class="built_in">console</span>.error);</span><br><span class="line"></span><br><span class="line">redisClient.on(<span class="string">'message'</span>, (channelName, msg: <span class="built_in">String</span>) =&gt; &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(`$&#123;channelName&#125;: $&#123;msg&#125;`);</span><br><span class="line">  <span class="keyword">if</span> (msg === <span class="string">'/unsubscribe'</span>) &#123;</span><br><span class="line">    redisClient.unsubscribe(channelName);</span><br><span class="line">  &#125; <span class="keyword">else</span> <span class="keyword">if</span> (msg.startsWith(<span class="string">'/subscribe'</span>)) &#123;</span><br><span class="line">    <span class="keyword">let</span> channel = msg.split(<span class="string">' '</span>).slice(<span class="number">1</span>).join(<span class="string">' '</span>);</span><br><span class="line">    subscribe(redisClient, channel);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">redisClient.on(<span class="string">'unsubscribe'</span>, (channelName, count) =&gt; &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(`unsubscribing from $&#123;channelName&#125;. Client is now listening to $&#123;count&#125; channel(s)`);</span><br><span class="line">  <span class="keyword">if</span> (count === <span class="number">0</span>) &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">'no more subscriptions; exiting…'</span>);</span><br><span class="line">    process.exit();</span><br><span class="line">  &#125;</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">redisClient.on(<span class="string">'subscribe'</span>, (channelName, count) =&gt; &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(`listening on channel: $&#123;channelName&#125;. Client is now listening to $&#123;count&#125; channel(s)`);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">subscribe(redisClient, channelName);</span><br></pre></td></tr></table></figure><p><img src="startsWith-does-not-exist.png" alt="startsWith does not exist on type &#39;String&#39;"></p><p>Clearly, we need to teach the compiler about <code>startsWith</code> (Node, which is what we’ll be running on, has this method already defined on the String prototype… we just need to make the compiler happy).</p><p>I came across a way to do this <a href="http://www.mzan.com/article/36432983-extension-methods-in-typescript-system.shtml" target="_blank" rel="external">here</a>. It is based on “global augmentation”:</p><blockquote>TypeScript also has the notion of global augmentations of the form <code>declare global { }</code>. This allows modules to augment global types such as <code>Array</code> if necessary.<footer><cite><a href="https://www.typescriptlang.org/docs/release-notes/typescript-1.8.html" target="_blank" rel="external">Augmenting global/module scope from modules</a></cite></footer></blockquote><p>An example of augmenting <code>Array</code> is given in the <a href="https://www.typescriptlang.org/docs/release-notes/typescript-1.8.html" target="_blank" rel="external">1.8 release notes</a>:</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Ensure this is treated as a module.</span></span><br><span class="line"><span class="keyword">export</span> &#123;&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">declare</span> global &#123;</span><br><span class="line">    <span class="interface"><span class="keyword">interface</span> Array&lt;T&gt; </span>&#123;</span><br><span class="line">        mapToNumbers(): <span class="built_in">number</span>[];</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Following this pattern, we can fix our issue with:</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// typingslocal/globals/runtime/index.d.ts</span></span><br><span class="line"><span class="keyword">export</span> &#123;&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">declare</span> global &#123;</span><br><span class="line">  <span class="interface"><span class="keyword">interface</span> String </span>&#123;</span><br><span class="line">    startsWith(searchString: <span class="built_in">string</span>, position?: <span class="built_in">number</span>): <span class="built_in">boolean</span>;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Note: if the use of an empty export to ensure the file is treated as a module doesn’t make sense to you, read <a href="https://basarat.gitbooks.io/typescript/content/docs/project/modules.html" target="_blank" rel="external">this</a>.</p><p>You should now have no compiler errors and be able to run the 2 scripts as shown in the demo at the start of this post.</p><h1 id="Conclusion"><a href="#Conclusion" class="headerlink" title="Conclusion"></a>Conclusion</h1><p>This post was meant as a “how-to” for people (and by someone) just getting started with Typescript. We’ve seen a lot of friction from the compiler and zero opportunities for it to help us (using JS would have been much easier for this demo). This can be expected to change as we start defining our own types and our code base gets larger :)</p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h1 id=&quot;Intro&quot;&gt;&lt;a href=&quot;#Intro&quot; class=&quot;headerlink&quot; title=&quot;Intro&quot;&gt;&lt;/a&gt;Intro&lt;/h1&gt;&lt;p&gt;The intention was to write some demo code to see what prob
      
    
    </summary>
    
      <category term="programming" scheme="http://justincalleja.com/categories/programming/"/>
    
    
      <category term="node" scheme="http://justincalleja.com/tags/node/"/>
    
      <category term="redis" scheme="http://justincalleja.com/tags/redis/"/>
    
      <category term="typescript" scheme="http://justincalleja.com/tags/typescript/"/>
    
  </entry>
  
  <entry>
    <title>Serving a Webpack bundle in Spring Boot</title>
    <link href="http://justincalleja.com/2016/04/17/serving-a-webpack-bundle-in-spring-boot/"/>
    <id>http://justincalleja.com/2016/04/17/serving-a-webpack-bundle-in-spring-boot/</id>
    <published>2016-04-17T00:00:00.000Z</published>
    <updated>2020-04-07T09:25:01.197Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Intro"><a href="#Intro" class="headerlink" title="Intro"></a>Intro</h1><p>This post demos an example of using <a href="https://webpack.github.io/" target="_blank" rel="external">Webpack</a> to bundle a frontend project and <a href="https://maven.apache.org/" target="_blank" rel="external">Maven</a> to package it up in a <a href="https://docs.oracle.com/javase/tutorial/deployment/jar/index.html" target="_blank" rel="external">jar</a> and include it in a <a href="http://projects.spring.io/spring-boot/" target="_blank" rel="external">Spring Boot</a> app to serve it.</p><p>The example in its final state is up on <a href="https://github.com/justin-calleja/webpack-mvn" target="_blank" rel="external">Github</a>.</p><h1 id="Getting-started"><a href="#Getting-started" class="headerlink" title="Getting started"></a>Getting started</h1><p>We’ll start by creating the 3 following projects:</p><ul><li>parent</li><li>fe</li><li>be</li></ul><p><code>parent</code> is just a convenient way to package both our other 2 modules up in one go. It only consists of the following <code>pom.xml</code> file:</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="title">project</span> <span class="attribute">xmlns</span>=<span class="value">"http://maven.apache.org/POM/4.0.0"</span> <span class="attribute">xmlns:xsi</span>=<span class="value">"http://www.w3.org/2001/XMLSchema-instance"</span> <span class="attribute">xsi:schemaLocation</span>=<span class="value">"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="title">modelVersion</span>&gt;</span>4.0.0<span class="tag">&lt;/<span class="title">modelVersion</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="title">groupId</span>&gt;</span>com.tmp<span class="tag">&lt;/<span class="title">groupId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="title">artifactId</span>&gt;</span>parent<span class="tag">&lt;/<span class="title">artifactId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="title">version</span>&gt;</span>0.0.1-SNAPSHOT<span class="tag">&lt;/<span class="title">version</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="title">packaging</span>&gt;</span>pom<span class="tag">&lt;/<span class="title">packaging</span>&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="title">modules</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">module</span>&gt;</span>../fe<span class="tag">&lt;/<span class="title">module</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">module</span>&gt;</span>../be<span class="tag">&lt;/<span class="title">module</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="title">modules</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">project</span>&gt;</span></span><br></pre></td></tr></table></figure><p>That way we can <code>mvn clean install</code> and it will install both our other 2 modules.</p><h1 id="The-frontend"><a href="#The-frontend" class="headerlink" title="The frontend"></a>The frontend</h1><p><code>fe</code> will be our frontend module. It’ll mostly feature JavaScript technology, but since we’re aiming to include this in a Spring Boot app, we’ll need to package it up in a jar file. We’ll be using the <a href="https://github.com/eirslett/frontend-maven-plugin" target="_blank" rel="external">frontend-maven-plugin</a> to do this as shown in <code>fe/pom.xml</code> below:</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br></pre></td><td class="code"><pre><span class="line"><span class="pi">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="title">project</span> <span class="attribute">xmlns</span>=<span class="value">"http://maven.apache.org/POM/4.0.0"</span> <span class="attribute">xmlns:xsi</span>=<span class="value">"http://www.w3.org/2001/XMLSchema-instance"</span> <span class="attribute">xsi:schemaLocation</span>=<span class="value">"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="title">modelVersion</span>&gt;</span>4.0.0<span class="tag">&lt;/<span class="title">modelVersion</span>&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="title">groupId</span>&gt;</span>com.tmp<span class="tag">&lt;/<span class="title">groupId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="title">artifactId</span>&gt;</span>fe<span class="tag">&lt;/<span class="title">artifactId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="title">version</span>&gt;</span>0.0.1-SNAPSHOT<span class="tag">&lt;/<span class="title">version</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="title">packaging</span>&gt;</span>jar<span class="tag">&lt;/<span class="title">packaging</span>&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="title">build</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">plugins</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="title">plugin</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">groupId</span>&gt;</span>com.github.eirslett<span class="tag">&lt;/<span class="title">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">artifactId</span>&gt;</span>frontend-maven-plugin<span class="tag">&lt;/<span class="title">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">version</span>&gt;</span>0.0.27<span class="tag">&lt;/<span class="title">version</span>&gt;</span></span><br><span class="line"></span><br><span class="line">        <span class="tag">&lt;<span class="title">executions</span>&gt;</span></span><br><span class="line"></span><br><span class="line">          <span class="tag">&lt;<span class="title">execution</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="title">id</span>&gt;</span>install node and npm<span class="tag">&lt;/<span class="title">id</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="title">goals</span>&gt;</span></span><br><span class="line">              <span class="tag">&lt;<span class="title">goal</span>&gt;</span>install-node-and-npm<span class="tag">&lt;/<span class="title">goal</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="title">goals</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="title">configuration</span>&gt;</span></span><br><span class="line">              <span class="tag">&lt;<span class="title">nodeVersion</span>&gt;</span>v4.2.1<span class="tag">&lt;/<span class="title">nodeVersion</span>&gt;</span></span><br><span class="line">              <span class="tag">&lt;<span class="title">npmVersion</span>&gt;</span>3.5.3<span class="tag">&lt;/<span class="title">npmVersion</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="title">configuration</span>&gt;</span></span><br><span class="line">          <span class="tag">&lt;/<span class="title">execution</span>&gt;</span></span><br><span class="line"></span><br><span class="line">          <span class="tag">&lt;<span class="title">execution</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="title">id</span>&gt;</span>npm install<span class="tag">&lt;/<span class="title">id</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="title">goals</span>&gt;</span></span><br><span class="line">              <span class="tag">&lt;<span class="title">goal</span>&gt;</span>npm<span class="tag">&lt;/<span class="title">goal</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="title">goals</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="title">configuration</span>&gt;</span></span><br><span class="line">              <span class="tag">&lt;<span class="title">arguments</span>&gt;</span>install<span class="tag">&lt;/<span class="title">arguments</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="title">configuration</span>&gt;</span></span><br><span class="line">          <span class="tag">&lt;/<span class="title">execution</span>&gt;</span></span><br><span class="line"></span><br><span class="line">          <span class="tag">&lt;<span class="title">execution</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="title">id</span>&gt;</span>npm run build<span class="tag">&lt;/<span class="title">id</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="title">goals</span>&gt;</span></span><br><span class="line">              <span class="tag">&lt;<span class="title">goal</span>&gt;</span>npm<span class="tag">&lt;/<span class="title">goal</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="title">goals</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="title">configuration</span>&gt;</span></span><br><span class="line">              <span class="tag">&lt;<span class="title">arguments</span>&gt;</span>run build<span class="tag">&lt;/<span class="title">arguments</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="title">configuration</span>&gt;</span></span><br><span class="line">          <span class="tag">&lt;/<span class="title">execution</span>&gt;</span></span><br><span class="line"></span><br><span class="line">        <span class="tag">&lt;/<span class="title">executions</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="title">plugin</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="title">plugins</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="title">build</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">project</span>&gt;</span></span><br></pre></td></tr></table></figure><p>The gist is that this plugin will install Node and npm as well as our npm dependencies, and build the project via <code>npm run build</code>. As you can see, we’re specifying the Node and npm versions to install. These exact versions are downloaded if not found in the project in question irrespective of which versions of this software may (or may not) already exist on the machine you’re building on (making for repeatable builds on different machines).</p><p>Next, we’ll define our <code>build</code> npm script in our <code>package.json</code>:</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  "<span class="attribute">name</span>": <span class="value"><span class="string">"fe"</span></span>,</span><br><span class="line">  "<span class="attribute">version</span>": <span class="value"><span class="string">"0.0.1-SNAPSHOT"</span></span>,</span><br><span class="line">  "<span class="attribute">description</span>": <span class="value"><span class="string">""</span></span>,</span><br><span class="line">  "<span class="attribute">main</span>": <span class="value"><span class="string">"./app"</span></span>,</span><br><span class="line">  "<span class="attribute">scripts</span>": <span class="value">&#123;</span><br><span class="line">    "<span class="attribute">build</span>": <span class="value"><span class="string">"webpack -p"</span></span><br><span class="line">  </span>&#125;</span>,</span><br><span class="line">  "<span class="attribute">author</span>": <span class="value"><span class="string">""</span></span>,</span><br><span class="line">  "<span class="attribute">license</span>": <span class="value"><span class="string">"ISC"</span></span>,</span><br><span class="line">  "<span class="attribute">devDependencies</span>": <span class="value">&#123;</span><br><span class="line">    "<span class="attribute">webpack</span>": <span class="value"><span class="string">"1.12.9"</span></span>,</span><br><span class="line">    "<span class="attribute">webpack-dev-server</span>": <span class="value"><span class="string">"1.14.0"</span></span><br><span class="line">  </span>&#125;</span><br><span class="line"></span>&#125;</span><br></pre></td></tr></table></figure><p>We’re simply running <code>webpack -p</code> to build for production (i.e. the bundle will be minified). Once you install the npm dependencies listed here (either through the Maven plugin or by running <code>npm install</code>), you’ll get a local copy of <code>webpack</code> in your <code>node_modules</code> directory. In <code>node_modules</code>, you’ll also get a <code>.bin</code> directory housing any scripts specified as binaries in any installed node modules.</p><p>So for instance, <code>node_modules/webpack/package.json</code> has the following file specified as a binary:</p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">"bin": &#123;</span><br><span class="line">  "webpack": "./bin/webpack.js"</span><br><span class="line">&#125;,</span><br></pre></td></tr></table></figure><p>This means there will be a link to the file <code>node_modules/webpack/bin/webpack.js</code> in <code>node_modules/.bin/</code>, and this link will have the name <code>webpack</code> (the key used in the <code>bin</code> object above).</p><p>Additionally, anything in <code>node_modules/.bin</code> will be on your PATH when you run the <code>npm scripts</code> specified in your <code>package.json</code>. i.e. <code>webpack</code> will be on your PATH when you run npm scripts through npm such that you don’t need to do the following:</p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">"scripts": &#123;</span><br><span class="line">  "build": "./node_modules/.bin/webpack -p"</span><br><span class="line">&#125;,</span><br></pre></td></tr></table></figure><p>You can simply use <code>webpack</code>. npm effectively <a href="http://linux.die.net/man/1/env" target="_blank" rel="external">alters your environment</a> before running the scripts you tell it to run.</p><p>But Webpack needs to be configured to do anything for us - so we’ll do that next (<code>fe/webpack.config.js</code>):</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> packageJSON = <span class="built_in">require</span>(<span class="string">'./package.json'</span>);</span><br><span class="line"><span class="keyword">var</span> path = <span class="built_in">require</span>(<span class="string">'path'</span>);</span><br><span class="line"><span class="keyword">var</span> webpack = <span class="built_in">require</span>(<span class="string">'webpack'</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> PATHS = &#123;</span><br><span class="line">  build: path.join(__dirname, <span class="string">'target'</span>, <span class="string">'classes'</span>, <span class="string">'META-INF'</span>, <span class="string">'resources'</span>, <span class="string">'webjars'</span>, packageJSON.name, packageJSON.version)</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  entry: <span class="string">'./app/index.js'</span>,</span><br><span class="line"></span><br><span class="line">  output: &#123;</span><br><span class="line">    path: PATHS.build,</span><br><span class="line">    filename: <span class="string">'app-bundle.js'</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>We’re specifying <code>./app/index.js</code> as our entry point. This script, along with anything else it pulls in by <code>require</code>ing it, will be bundled up in a file named <code>app-bundle.js</code> in the directory: <a href="https://nodejs.org/docs/latest/api/globals.html#globals_dirname" target="_blank" rel="external">__dirname</a> + <code>&#39;/target/classes/META-INF/resources/webjars/fe/0.0.1-SNAPSHOT&#39;</code>.</p><p>This might seem like a peculiar output destination. By choosing <code>target/classes</code>, Maven will include Webpack’s output in the final product for this module, the jar file. We could have chosen something like <code>src/main/resources</code> which would have had a similar effect, but then running <code>mvn clean</code> would not delete Webpack’s output (something we want to do when cleaning).</p><p>In passing, note the <code>/META-INF/resources</code> part of the path we’re using. Containers implementing the Servlet 3.0 specification should be able to serve assets in a jar’s <code>/META-INF/resources</code> without any configuration. However, we’ll be explicitly serving our Webpack build via Spring configuration.</p><p>Next, let’s write some simple code just to have something to bundle up:</p><p><code>fe/app/index.js</code>:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> greeter = <span class="built_in">require</span>(<span class="string">'./greeter'</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> greeting = greeter.greet();</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (<span class="keyword">typeof</span> <span class="built_in">document</span> !== <span class="string">'undefined'</span>) &#123;</span><br><span class="line">  <span class="keyword">var</span> el = <span class="built_in">document</span>.createElement(<span class="string">'h1'</span>);</span><br><span class="line">  el.innerHTML = greeting;</span><br><span class="line">  <span class="built_in">document</span>.body.appendChild(el);</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(greeting);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>fe/app/greeter.js</code>:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  greet: <span class="function"><span class="keyword">function</span>(<span class="params">name</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> name ? <span class="string">'Hello '</span> + name + <span class="string">'!'</span> : <span class="string">'Hello World!'</span>;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Notice how in <code>fe/app/index.js</code> we’re guarding against not having a <code>document</code> object. This isn’t really necessary as we intend to write a <strong>frontend</strong> app, but it’s interesting to note how we can get this code to work outside the browser. It is still an npm package and we could publish it to a private or public registry and re-use it elsewhere - maybe in an app that doesn’t use this module as a frontend.</p><p>Running <code>mvn clean install</code> should now give you the jar we’ll be using from our backend.</p><h1 id="The-backend"><a href="#The-backend" class="headerlink" title="The backend"></a>The backend</h1><p>Our backend’s <code>pom.xml</code>:</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="pi">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="title">project</span> <span class="attribute">xmlns</span>=<span class="value">"http://maven.apache.org/POM/4.0.0"</span> <span class="attribute">xmlns:xsi</span>=<span class="value">"http://www.w3.org/2001/XMLSchema-instance"</span></span><br><span class="line">  <span class="attribute">xsi:schemaLocation</span>=<span class="value">"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="title">modelVersion</span>&gt;</span>4.0.0<span class="tag">&lt;/<span class="title">modelVersion</span>&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="title">groupId</span>&gt;</span>com.tmp<span class="tag">&lt;/<span class="title">groupId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="title">artifactId</span>&gt;</span>be<span class="tag">&lt;/<span class="title">artifactId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="title">version</span>&gt;</span>0.0.1-SNAPSHOT<span class="tag">&lt;/<span class="title">version</span>&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="title">properties</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">java.version</span>&gt;</span>1.8<span class="tag">&lt;/<span class="title">java.version</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="title">properties</span>&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="title">parent</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="title">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">artifactId</span>&gt;</span>spring-boot-starter-parent<span class="tag">&lt;/<span class="title">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">version</span>&gt;</span>1.3.3.RELEASE<span class="tag">&lt;/<span class="title">version</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="title">parent</span>&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="title">dependencies</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">dependency</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="title">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="title">groupId</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="title">artifactId</span>&gt;</span>spring-boot-starter-web<span class="tag">&lt;/<span class="title">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="title">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">dependency</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="title">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="title">groupId</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="title">artifactId</span>&gt;</span>spring-boot-devtools<span class="tag">&lt;/<span class="title">artifactId</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="title">optional</span>&gt;</span>true<span class="tag">&lt;/<span class="title">optional</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="title">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">dependency</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="title">groupId</span>&gt;</span>com.tmp<span class="tag">&lt;/<span class="title">groupId</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="title">artifactId</span>&gt;</span>fe<span class="tag">&lt;/<span class="title">artifactId</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="title">version</span>&gt;</span>0.0.1-SNAPSHOT<span class="tag">&lt;/<span class="title">version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="title">dependency</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="title">dependencies</span>&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="title">build</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">plugins</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="title">plugin</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="title">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">artifactId</span>&gt;</span>spring-boot-maven-plugin<span class="tag">&lt;/<span class="title">artifactId</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="title">plugin</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="title">plugins</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="title">build</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">project</span>&gt;</span></span><br></pre></td></tr></table></figure><p>With the pom in place, we can start our configuration in <code>be/src/main/java/com/tmp/App.java</code>:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.tmp;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.slf4j.Logger;</span><br><span class="line"><span class="keyword">import</span> org.slf4j.LoggerFactory;</span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.annotation.Value;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.SpringApplication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.autoconfigure.SpringBootApplication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.ApplicationListener;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.event.ContextRefreshedEvent;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.servlet.config.annotation.EnableWebMvc;</span><br><span class="line"></span><br><span class="line"><span class="annotation">@EnableWebMvc</span></span><br><span class="line"><span class="annotation">@SpringBootApplication</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">App</span> <span class="keyword">implements</span> <span class="title">ApplicationListener</span>&lt;<span class="title">ContextRefreshedEvent</span>&gt; </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> Logger LOG = LoggerFactory.getLogger(App.class);</span><br><span class="line"></span><br><span class="line">    <span class="annotation">@Value</span>(<span class="string">"$&#123;spring.profiles.active&#125;"</span>)</span><br><span class="line">    <span class="keyword">protected</span> String springProfilesActive;</span><br><span class="line"></span><br><span class="line">    <span class="annotation">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onApplicationEvent</span><span class="params">(ContextRefreshedEvent event)</span> </span>&#123;</span><br><span class="line">        LOG.info(<span class="string">"======================================="</span>);</span><br><span class="line">        LOG.info(<span class="string">"App running with active profiles: &#123;&#125;"</span>, springProfilesActive);</span><br><span class="line">        LOG.info(<span class="string">"======================================="</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        SpringApplication.run(App.class, args);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>It’s mostly annotation driven:</p><p><a href="http://docs.spring.io/spring-boot/docs/current/api/" target="_blank" rel="external">@SpringBootApplication</a> = <a href="http://docs.spring.io/spring-framework/docs/4.2.5.RELEASE/javadoc-api/org/springframework/context/annotation/Configuration.html" target="_blank" rel="external">@Configuration</a> + <a href="http://docs.spring.io/spring-boot/docs/current/api/" target="_blank" rel="external">@EnableAutoConfiguration</a> + <a href="http://docs.spring.io/spring-framework/docs/4.2.5.RELEASE/javadoc-api/org/springframework/context/annotation/ComponentScan.html" target="_blank" rel="external">@ComponentScan</a>.</p><p><a href="https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/servlet/config/annotation/EnableWebMvc.html" target="_blank" rel="external">@EnableWebMvc</a> = Adds the configuration in <a href="https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.html" target="_blank" rel="external">WebMvcConfigurationSupport</a> which you can then override as necessary.</p><p>I’m also adding some superfluous things like implementing <code>ApplicationListener&lt;ContextRefreshedEvent&gt;</code> to log out the active profile when the <a href="http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/ApplicationContext.html" target="_blank" rel="external">ApplicationContext</a> gets initialized or is refreshed (i.e. to log on server startup). We don’t actually need this, but I’ll be going off on a bit of a tangent when using the <a href="https://webpack.github.io/docs/webpack-dev-server.html" target="_blank" rel="external">webpack-dev-server</a> later in this post. We’ll then need to enable <a href="https://en.wikipedia.org/wiki/Cross-origin_resource_sharing" target="_blank" rel="external">CORS</a> from our Spring Boot server. Hence, I’m logging out the active profile on start up to show the environment the server is running in (as CORS will only be enabled if the server is running in <code>dev</code> mode). Plus I just like logging things like this on startup.</p><p>For more on logging info on app startup you might be interested in <a href="https://www.youtube.com/watch?v=UjYv7HfTrlc" target="_blank" rel="external">this</a> (what originally got me to start doing this in Spring apps).</p><p>Our configuration continues in <code>be/src/main/java/com/tmp/WebMvcConfig.java</code> which is responsible for configuring beans to do with the web side of things:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.tmp;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.Bean;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.Configuration;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.Profile;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.servlet.config.annotation.CorsRegistry;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.servlet.config.annotation.WebMvcConfigurer;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;</span><br><span class="line"></span><br><span class="line"><span class="annotation">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">WebMvcConfig</span> <span class="keyword">extends</span> <span class="title">WebMvcConfigurerAdapter</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> String[] CLASSPATH_RESOURCE_LOCATIONS = &#123; <span class="string">"classpath:/public/"</span> &#125;;</span><br><span class="line"></span><br><span class="line">    <span class="annotation">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">addResourceHandlers</span><span class="params">(ResourceHandlerRegistry registry)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">super</span>.addResourceHandlers(registry);</span><br><span class="line">        <span class="keyword">if</span> (!registry.hasMappingForPattern(<span class="string">"/webjars/**"</span>)) &#123;</span><br><span class="line">            registry.addResourceHandler(<span class="string">"/webjars/**"</span>).addResourceLocations(<span class="string">"classpath:/META-INF/resources/webjars/"</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (!registry.hasMappingForPattern(<span class="string">"/**"</span>)) &#123;</span><br><span class="line">            registry.addResourceHandler(<span class="string">"/**"</span>).addResourceLocations(CLASSPATH_RESOURCE_LOCATIONS);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>We’re adding 2 static asset resource handlers. Our server will look in <code>classpath:/META-INF/resources/webjars/</code> for any requests starting with <code>/webjars/</code>. So when our <code>fe</code> project is all packaged up and on the classpath, since it contains the following file: <code>META-INF/resources/webjars/fe/0.0.1-SNAPSHOT/app-bundle.js</code>, a request such as <code>http://localhost:8090/webjars/fe/0.0.1-SNAPSHOT/app-bundle.js</code> should serve that file as expected.</p><p>But doing so will only get you a bunch of JavaScript source code displayed in your browser - which is why I’ve added an “anything else” pattern (i.e. <code>/**</code>) and mapped it to search in <code>classpath:/public</code> (another example of this <a href="https://spring.io/blog/2013/12/19/serving-static-web-content-with-spring-boot" target="_blank" rel="external">here</a>).</p><p>Now, since the contents of <code>src/main/resources</code> in Mavenized projects end up packaged in your jar file, we can put our static assets (like <code>index.html</code> below) in <code>be/src/main/resource/public/</code> and they will be served from the classpath by our server:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="doctype">&lt;!DOCTYPE html&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="title">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="title">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="title">meta</span> <span class="attribute">charset</span>=<span class="value">"UTF-8"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="title">title</span>&gt;</span>App<span class="tag">&lt;/<span class="title">title</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="title">body</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="title">script</span> <span class="attribute">src</span>=<span class="value">"/webjars/fe/0.0.1-SNAPSHOT/app-bundle.js"</span>&gt;</span><span class="undefined"></span><span class="tag">&lt;/<span class="title">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">html</span>&gt;</span></span><br></pre></td></tr></table></figure><p>One final thing, add <code>application.properties</code> to <code>src/main/resources</code>:</p><figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">spring<span class="class">.profiles</span><span class="class">.active</span>=dev</span><br><span class="line">server.port=<span class="number">8090</span></span><br></pre></td></tr></table></figure><p>This gets picked up auto-magically via Spring Boot configuration.</p><p>At this point you should be able to start up the server (either through your IDE or by running <code>mvn clean package &amp;&amp; java -jar ./target/be-0.0.1-SNAPSHOT.jar</code> in <code>be</code>), hit <code>http://localhost:8090/index.html</code> and get “Hello World!” back.</p><p>You will notice that leaving off the <code>index.html</code> part of the URL will break things. We can quickly fix this by following the advice in this <a href="http://stackoverflow.com/a/27383522" target="_blank" rel="external">SO answer by Dave Syer</a>.</p><p>i.e. we can add the following to <code>WebMvcConfig</code> (note: if you’re using the <code>spring-boot-devtools</code> and it’s still not working after adding this change, try manually re-starting the server):</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">addViewControllers</span><span class="params">(ViewControllerRegistry registry)</span> </span>&#123;</span><br><span class="line">    registry.addViewController(<span class="string">"/"</span>).setViewName(<span class="string">"forward:/index.html"</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="webpack-dev-server"><a href="#webpack-dev-server" class="headerlink" title="webpack-dev-server"></a>webpack-dev-server</h1><p>Fast feedback is cool and healthy. We currently have a process to bundle our <code>fe</code> app into a <code>jar</code> and serve these assets via our Boot app, which is great when we’re all done developing our frontend code. However, it’s not something you want to do while actually building your frontend code as it’s too time consuming and soul crushing.</p><p>You might consider writing a simple <a href="http://expressjs.com/" target="_blank" rel="external">Express</a> app and serve your Webpack generated bundles from it while developing. At least you’d skip the Maven build. That would be a start. You’d also need to watch files and build them with Webpack unless you fancy manually running Webpack when you’re done changing files and possibly re-starting the Node server (unless this dev server is not caching the built files).</p><p>Good thing this <a href="http://expressjs.com/" target="_blank" rel="external">Express</a> based server is already written for us. It’s called <a href="https://webpack.github.io/docs/webpack-dev-server.html" target="_blank" rel="external">webpack-dev-server</a> and we’ll use it to serve Webpack’s output as we make changes to our code. (Note: in case you already have an Express app and you want to bake in Webpack’s file watching and bundling, you can use the <a href="https://webpack.github.io/docs/webpack-dev-middleware.html" target="_blank" rel="external">webpack-dev-middleware</a>).</p><p>To start the dev server you first need to install it. As we’ve listed it as a <code>devDependency</code> in our <code>package.json</code> above, you could run it with <code>./node_modules/.bin/webpack-dev-server</code>, or you could install it globally with <code>npm i -g webpack-dev-server</code> (after which you can just run <code>webpack-dev-server</code> to run it).</p><p>Of course, before running the server, our frontend code needs to run on a web page so we’ll need some kind of HTML file to require the bundle we’re building through Webpack. To do this, we could use the <a href="https://github.com/ampedandwired/html-webpack-plugin" target="_blank" rel="external">html-webpack-plugin</a>, but for the sake of transparency, we’ll add the following in <code>fe/tmp/index.html</code>:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="doctype">&lt;!DOCTYPE html&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="title">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="title">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="title">meta</span> <span class="attribute">charset</span>=<span class="value">"UTF-8"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="title">title</span>&gt;</span>App<span class="tag">&lt;/<span class="title">title</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="title">body</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="title">script</span> <span class="attribute">src</span>=<span class="value">"../assets/app-bundle.js"</span>&gt;</span><span class="undefined"></span><span class="tag">&lt;/<span class="title">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">html</span>&gt;</span></span><br></pre></td></tr></table></figure><p>Now you might be wondering where <code>assets</code> came from? It’s the <a href="https://github.com/webpack/docs/wiki/configuration#outputpublicpath" target="_blank" rel="external">output.publicPath</a> we’re still missing in our <code>webpack.config.js</code>, and which you can add like so:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// ...</span></span><br><span class="line">  output: &#123;</span><br><span class="line">    path: PATHS.build,</span><br><span class="line">    publicPath: <span class="string">'/assets/'</span>,</span><br><span class="line">    filename: <span class="string">'app-bundle.js'</span></span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure><p>From the docs, <code>publicPath</code> is the path from which the webpack-dev-server will serve the bundles created by Webpack:</p><blockquote>The Webpack Dev Server also uses this to determine the path where the output files are expected to be served from<footer><cite><a href="https://github.com/webpack/docs/wiki/configuration#outputpublicpath" target="_blank" rel="external">output.publicPath doc</a></cite></footer></blockquote><p>(Note: I used <code>/assets/</code> to keep with the example in the docs. In our case, since our HTML is in the <code>tmp</code> directory, it would probably make more sense to set the <code>publicPath</code> to <code>/tmp/</code>. The <code>src</code> in our script tag would then be a simpler: <code>app-bundle.js</code>).</p><p>We’re finally ready to see this in action. Assuming you’re in <code>fe</code>, run the server with the <a href="https://webpack.github.io/docs/webpack-dev-server.html#inline-mode" target="_blank" rel="external">–inline</a> and <a href="https://webpack.github.io/docs/webpack-dev-server.html#hot-module-replacement" target="_blank" rel="external">–hot</a> arguments: <code>webpack-dev-server --inline --hot</code> (you might want to add this as an <a href="https://docs.npmjs.com/misc/scripts" target="_blank" rel="external">npm script</a> as we’ve done with <code>build</code> above).</p><p>You should now be able to hit <code>http://localhost:8080/tmp/index.html</code> and get:</p><p><img src="hello-world-webpack.png" alt="Hello World from webpack-dev-server" title="Hello World from webpack-dev-server"></p><p><code>http://localhost:8080/assets/app-bundle.js</code> is the request our HTML file makes to get the bundle built by Webpack. Note that this is content which is served from memory i.e. when using <code>webpack-dev-server</code> bundles like <code>app-bundle.js</code> are not saved to disk. They are (re)generated on file changes (the files which make up our bundles). If you want to hit the disk, you can run Webpack itself - not the dev server - as we have through npm above.</p><p>Now, notice the console output in the screen shot above. If you have that, then hot module replacement is in place and you can go ahead and change <code>fe/app/index.js</code> or <code>fe/app/greeter.js</code> and see the changes in your browser after saving and without re-loading the page… WIN!</p><h1 id="CORS-in-development"><a href="#CORS-in-development" class="headerlink" title="CORS in development"></a>CORS in development</h1><p>Things are looking good. There is, however, one issue we’ll have to face as soon as our app graduates from the “hello world” level. Since our frontend assets are being served from a different server than the one serving our backend data (on a different port), we’re going to have to enable CORS requests originating from <code>localhost:8080</code> (our webpack-dev-server).</p><p>Doing so is simple enough in Spring Boot. Just add the following to <code>be/src/main/java/com/tmp/WebMvcConfig.java</code>:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Bean</span></span><br><span class="line"><span class="annotation">@Profile</span>(<span class="string">"dev"</span>)</span><br><span class="line"><span class="function"><span class="keyword">public</span> WebMvcConfigurer <span class="title">corsConfigurer</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> WebMvcConfigurerAdapter() &#123;</span><br><span class="line">        <span class="annotation">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">addCorsMappings</span><span class="params">(CorsRegistry registry)</span> </span>&#123;</span><br><span class="line">            registry.addMapping(<span class="string">"/api/**"</span>).allowedOrigins(<span class="string">"http://localhost:8080"</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>So, when our server is running in <code>dev</code> mode, any requests to <code>/api/**</code> coming from <code>http://localhost:8080</code> will be allowed.</p><p>Next, if we want to try this out, we’re going to need at least one REST endpoint to work with:</p><p><code>be/src/main/java/com/tmp/GreeterController.java</code>:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.tmp;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.time.LocalDateTime;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Controller;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.PathVariable;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RequestMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RequestMethod;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.ResponseBody;</span><br><span class="line"></span><br><span class="line"><span class="annotation">@Controller</span></span><br><span class="line"><span class="annotation">@RequestMapping</span>(value = <span class="string">"/api/greetings"</span>)</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">GreeterController</span> </span>&#123;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> String template = <span class="string">"Hello, %s!"</span>;</span><br><span class="line"></span><br><span class="line">    <span class="annotation">@RequestMapping</span>(method = RequestMethod.GET, produces = &#123; <span class="string">"application/json"</span> &#125;)</span><br><span class="line">    <span class="keyword">public</span> <span class="annotation">@ResponseBody</span> <span class="function">Greeting <span class="title">greetNoName</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> Greeting(String.format(template, <span class="string">"World"</span>));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="annotation">@RequestMapping</span>(value = <span class="string">"/&#123;name&#125;"</span>, method = RequestMethod.GET, produces = &#123; <span class="string">"application/json"</span> &#125;)</span><br><span class="line">    <span class="keyword">public</span> <span class="annotation">@ResponseBody</span> <span class="function">Greeting <span class="title">greetName</span><span class="params">(<span class="keyword">final</span> @PathVariable String name)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> Greeting(String.format(template, name));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Greeting</span> </span>&#123;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> String content;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> LocalDateTime time;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">Greeting</span><span class="params">(String content)</span> </span>&#123;</span><br><span class="line">            <span class="keyword">this</span>.content = content;</span><br><span class="line">            <span class="keyword">this</span>.time = LocalDateTime.now();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> String <span class="title">getContent</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">this</span>.content;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> String <span class="title">getTime</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">this</span>.time.toString();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>This is straightforward enough. We can hit <code>/api/greetings/{name}</code> with an optional <code>{name}</code> path parameter and get back some JSON.</p><p>Finally, we can change our client (<code>fe/app/index.js</code>) to something like the following:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> greeter = <span class="built_in">require</span>(<span class="string">'./greeter'</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> greeting = greeter.greet();</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (<span class="keyword">typeof</span> <span class="built_in">document</span> !== <span class="string">'undefined'</span>) &#123;</span><br><span class="line">  <span class="keyword">var</span> apiEndpoint = <span class="string">'http://localhost:8090/api/greetings'</span>;</span><br><span class="line">  <span class="keyword">var</span> el = <span class="built_in">document</span>.createElement(<span class="string">'h1'</span>);</span><br><span class="line"></span><br><span class="line">  fetch(apiEndpoint + <span class="string">'/webpack'</span>).then(<span class="function"><span class="keyword">function</span>(<span class="params">response</span>) </span>&#123; </span><br><span class="line">    <span class="keyword">return</span> response.json();</span><br><span class="line">  &#125;).then(<span class="function"><span class="keyword">function</span>(<span class="params">obj</span>) </span>&#123;</span><br><span class="line">    el.innerHTML = greeting + <span class="string">'&lt;br&gt;'</span> + obj.content + <span class="string">'&lt;br&gt;At '</span> + obj.time;</span><br><span class="line">    <span class="built_in">document</span>.body.appendChild(el);</span><br><span class="line">  &#125;).catch(<span class="function"><span class="keyword">function</span>(<span class="params">err</span>) </span>&#123;</span><br><span class="line">    el.innerHTML = <span class="string">'oh no…'</span>;</span><br><span class="line">    <span class="built_in">document</span>.body.appendChild(el);</span><br><span class="line">  &#125;);</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(greeting);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>You can try commenting out and undoing the CORS configuration in our Spring app to see it’s effect in the browser as shown below (Note: you don’t need to restart the Spring Boot server either thanks to the <code>spring-boot-devtools</code> plugin):</p><p><img src="cors-disabled.png" alt="CORS disabled" title="CORS disabled"></p><p><img src="cors-enabled.png" alt="CORS enabled" title="CORS enabled"></p><p>Finally, to wrap things up, we can <code>cd</code> into our <code>parent</code> project and run <code>mvn clean install</code> to package and install our <code>fe</code> and <code>be</code>. You can then run the <code>be</code> jar with:</p><p><code>java -jar ./$PATH_TO_JAR/be-0.0.1-SNAPSHOT.jar --spring.profiles.active=prod</code></p><p>where <code>$PATH_TO_JAR</code> is either <code>be/target</code> or its location in your local maven repo.</p><p>Hitting <code>http://localhost:8090/index.html</code> should give you the same output as when running with both servers.</p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h1 id=&quot;Intro&quot;&gt;&lt;a href=&quot;#Intro&quot; class=&quot;headerlink&quot; title=&quot;Intro&quot;&gt;&lt;/a&gt;Intro&lt;/h1&gt;&lt;p&gt;This post demos an example of using &lt;a href=&quot;https://webpa
      
    
    </summary>
    
      <category term="programming" scheme="http://justincalleja.com/categories/programming/"/>
    
    
      <category term="java" scheme="http://justincalleja.com/tags/java/"/>
    
      <category term="spring boot" scheme="http://justincalleja.com/tags/spring-boot/"/>
    
      <category term="webpack" scheme="http://justincalleja.com/tags/webpack/"/>
    
  </entry>
  
  <entry>
    <title>Elixir Streams reload</title>
    <link href="http://justincalleja.com/2016/01/26/elixir-streams-reload/"/>
    <id>http://justincalleja.com/2016/01/26/elixir-streams-reload/</id>
    <published>2016-01-26T00:00:00.000Z</published>
    <updated>2020-04-07T09:25:01.191Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Intro"><a href="#Intro" class="headerlink" title="Intro"></a>Intro</h1><p>This post is based on <a href="http://drewolson.org/" target="_blank" rel="external">Drew Olson</a>‘s <a href="http://blog.drewolson.org/elixir-streams/" target="_blank" rel="external">Elixir Streams</a>. Since I’m just getting started with <a href="http://elixir-lang.org/" target="_blank" rel="external">Elixir</a>, I came across a few issues understanding the <a href="http://blog.drewolson.org/elixir-streams/#buildinganapiwithstreams" target="_blank" rel="external">“Building an API with Streams”</a> section in Drew’s post. This post is my attempt at breaking it down while learning about Elixir.</p><p>I’m using <a href="http://elixir-lang.org/" target="_blank" rel="external">Elixir</a> 1.2.0 (and <a href="http://www.erlang.org/" target="_blank" rel="external">Erlang</a> 18.1).</p><h2 id="Intro-some-more"><a href="#Intro-some-more" class="headerlink" title="Intro some more"></a>Intro some more</h2><ul><li>The code for the main example is up on <a href="https://github.com/justin-calleja/elixir-streams-reload" target="_blank" rel="external">Github</a></li><li>There is a <a href="#How_to_install_Elixir_with_asdf">How to install Elixir with asdf</a> section at the end if you don’t have Elixir and want a quick way of installing it</li><li>I will not be using the exact Github endpoint (e.g. <a href="https://github.com/api/v3/orgs/elixir-lang/repos" target="_blank" rel="external">https://github.com/api/v3/orgs/elixir-lang/repos</a>) used in Drew’s post because:<ul><li>I’m not familiar with the Github API</li><li>Couldn’t get the given endpoint to work after generating an access token</li><li>Got the data I wanted anyway using the endpoint in this post (no need for access tokens)</li><li>It cuts down on code :)</li></ul></li><li>This post is primarily a “learning devise”, by which I mean I intend to side track from the main intention below to explain (or mention and link to) Elixir basics. i.e. this post is not really about Elixir Streams although it features them. The original idea for this post was to learn some Elixir basics in the context of the app in Drew’s <a href="http://blog.drewolson.org/elixir-streams/#buildinganapiwithstreams" target="_blank" rel="external">“Building an API with Streams”</a> section.</li><li>Code example in the “Building an API with Streams” section in Drew’s post has been tweaked to work with Elixir version 1.2.0.</li><li><strong>This is a long and winding one…</strong> - you have been warned :)</li></ul><h1 id="The-intention"><a href="#The-intention" class="headerlink" title="The intention"></a>The intention</h1><p>We want to write an Elixir module to expose an Elixir based API around the <a href="https://developer.github.com/v3/" target="_blank" rel="external">Github REST API</a> in such a way as to hide pagination from users of our API. Our API will give users <a href="http://elixir-lang.org/docs/v1.2/elixir/Stream.html" target="_blank" rel="external">stream</a>s to work with. As we’ll see, this means we never hit Github unless the user actually reads from the stream, and we only paginate as much as necessary (depending on how much the user reads from the stream and how many pages Github has for the particular resource).</p><p>It’s probably best to go over this intention in more detail.</p><h2 id="How-to-fetch-Github-organization-repos-and-their-pagination"><a href="#How-to-fetch-Github-organization-repos-and-their-pagination" class="headerlink" title="How to fetch Github organization repos and their pagination"></a>How to fetch Github organization repos and their pagination</h2><p>We will only be concerned with a single endpoint from Github’s API in this post, namely, <em>listing the repositories of a specific organization</em>. So let’s start off with the <a href="https://github.com/elixir-lang" target="_blank" rel="external">elixir-lang</a> organization. If you open the following in a browser: <a href="https://api.github.com/orgs/elixir-lang/repos" target="_blank" rel="external">https://api.github.com/orgs/elixir-lang/repos</a>, you should get back something like:</p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">[</span><br><span class="line">  &#123;</span><br><span class="line">    "id": 1234714,</span><br><span class="line">      "name": "elixir",</span><br><span class="line">      "full_name": "elixir-lang/elixir",</span><br><span class="line">      ...</span><br><span class="line">  &#125;,</span><br><span class="line">  &#123;</span><br><span class="line">    "id": 1467845,</span><br><span class="line">    "name": "elixir-tmbundle",</span><br><span class="line">    "full_name": "elixir-lang/elixir-tmbundle",</span><br><span class="line">    ...</span><br><span class="line">  &#125;,</span><br><span class="line">  ...</span><br><span class="line">]</span><br></pre></td></tr></table></figure><p>Opening your browser’s dev tools, you’ll also be able to look at the HTTP response headers from the API (or <code>curl -i https://api.github.com/orgs/elixir-lang/repos | less</code> if you’re on a Unixy system). At the time of writing, you will see that there is no <code>Link</code> header for <code>elixir-lang</code> as it hasn’t got enough repos to necessitate pagination.</p><p>Maybe there’s a parameter to limit the number of returned repos - in which case, you’d be able to trigger pagination like that. But I’m too lazy to look into that so I’ll just pick something like: <a href="https://api.github.com/orgs/nodejs/repos" target="_blank" rel="external">https://api.github.com/orgs/nodejs/repos</a>, which gives back this <code>Link</code> header:</p><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="constant">Link:</span> &lt;<span class="symbol">https:</span>/<span class="regexp">/api.github.com/organizations</span><span class="regexp">/9950313/repos</span>?page=<span class="number">2</span>&gt;; rel=<span class="string">"next"</span>,</span><br><span class="line">      &lt;<span class="symbol">https:</span>/<span class="regexp">/api.github.com/organizations</span><span class="regexp">/9950313/repos</span>?page=<span class="number">3</span>&gt;; rel=<span class="string">"last"</span></span><br></pre></td></tr></table></figure><p>Using a tool like <a href="https://stedolan.github.io/jq/" target="_blank" rel="external">jq</a>, we can easily count how many repos we just got back:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ curl <span class="operator">-s</span> <span class="string">"https://api.github.com/orgs/nodejs/repos"</span> | jq <span class="string">'. | length'</span></span><br><span class="line"><span class="number">30</span></span><br></pre></td></tr></table></figure><p>So now we know that we’ll only ever get a maximum of 30 repos for each such request we make to Github. If the organization happens to have more than 30 repos, we’ll need to follow the link with <code>rel=&quot;next&quot;</code>, and so on, until there are no more repos to get - i.e. we need to paginate.</p><p><em>But</em>, we don’t want to paginate unless the user actually wants more data - which is why we give the user a stream.</p><h2 id="Quick-intro-to-streams"><a href="#Quick-intro-to-streams" class="headerlink" title="Quick intro to streams"></a>Quick intro to streams</h2><p>The thing about streams is… they’re lazy… and they’re enumerable.</p><p><a href="http://elixir-lang.org/docs/v1.2/elixir/Stream.html" target="_blank" rel="external">Stream</a> the Elixir module, like the <a href="http://elixir-lang.org/docs/v1.2/elixir/Enum.html" target="_blank" rel="external">Enum</a> module, works on <a href="http://elixir-lang.org/docs/v1.2/elixir/Enumerable.html" target="_blank" rel="external">Enumerable</a> things. But a stream itself is some kind of data structure which implements the Enumerable <a href="http://elixir-lang.org/getting-started/protocols.html" target="_blank" rel="external">protocol</a> (making it an Enumerable thing). This means that streams, like other Enumerables, <a href="https://github.com/elixir-lang/elixir/blob/v1.2/lib/elixir/lib/stream.ex#L1222-L1238" target="_blank" rel="external">implement</a>:</p><ul><li>Enumerable.count/1</li><li>Enumerable.member?/2</li><li>Enumerable.reduce/3</li></ul><p>just like all the following Enumerables (checkout <a href="https://github.com/elixir-lang/elixir" target="_blank" rel="external">elixir</a>):</p><figure class="highlight crystal"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">~<span class="regexp">/github-stuff/elixir</span><span class="variable">$ </span>egrep -<span class="constant">R</span> -n --exclude-dir=&#123;bin,\.git&#125; <span class="string">".*defimpl Enumerable.*"</span> .</span><br><span class="line">./<span class="class"><span class="keyword">lib</span>/<span class="title">elixir</span>/<span class="title">lib</span>/<span class="title">enum</span>.<span class="title">ex</span>:2748:<span class="title">defimpl</span> <span class="title">Enumerable</span>, <span class="title">for</span>: <span class="title">List</span> <span class="title">do</span></span></span><br><span class="line">./<span class="class"><span class="keyword">lib</span>/<span class="title">elixir</span>/<span class="title">lib</span>/<span class="title">enum</span>.<span class="title">ex</span>:2760:<span class="title">defimpl</span> <span class="title">Enumerable</span>, <span class="title">for</span>: <span class="title">Map</span> <span class="title">do</span></span></span><br><span class="line">./<span class="class"><span class="keyword">lib</span>/<span class="title">elixir</span>/<span class="title">lib</span>/<span class="title">enum</span>.<span class="title">ex</span>:2783:<span class="title">defimpl</span> <span class="title">Enumerable</span>, <span class="title">for</span>: <span class="title">Function</span> <span class="title">do</span></span></span><br><span class="line">./<span class="class"><span class="keyword">lib</span>/<span class="title">elixir</span>/<span class="title">lib</span>/<span class="title">file</span>/<span class="title">stream</span>.<span class="title">ex</span>:68:  <span class="title">defimpl</span> <span class="title">Enumerable</span> <span class="title">do</span></span></span><br><span class="line">./<span class="class"><span class="keyword">lib</span>/<span class="title">elixir</span>/<span class="title">lib</span>/<span class="title">gen_event</span>/<span class="title">stream</span>.<span class="title">ex</span>:58:<span class="title">defimpl</span> <span class="title">Enumerable</span>, <span class="title">for</span>: <span class="title">GenEvent</span>.<span class="title">Stream</span> <span class="title">do</span></span></span><br><span class="line">./<span class="class"><span class="keyword">lib</span>/<span class="title">elixir</span>/<span class="title">lib</span>/<span class="title">hash_dict</span>.<span class="title">ex</span>:220:<span class="title">defimpl</span> <span class="title">Enumerable</span>, <span class="title">for</span>: <span class="title">HashDict</span> <span class="title">do</span></span></span><br><span class="line">./<span class="class"><span class="keyword">lib</span>/<span class="title">elixir</span>/<span class="title">lib</span>/<span class="title">hash_set</span>.<span class="title">ex</span>:235:<span class="title">defimpl</span> <span class="title">Enumerable</span>, <span class="title">for</span>: <span class="title">HashSet</span> <span class="title">do</span></span></span><br><span class="line">./<span class="class"><span class="keyword">lib</span>/<span class="title">elixir</span>/<span class="title">lib</span>/<span class="title">io</span>/<span class="title">stream</span>.<span class="title">ex</span>:49:  <span class="title">defimpl</span> <span class="title">Enumerable</span> <span class="title">do</span></span></span><br><span class="line">./<span class="class"><span class="keyword">lib</span>/<span class="title">elixir</span>/<span class="title">lib</span>/<span class="title">map_set</span>.<span class="title">ex</span>:266:  <span class="title">defimpl</span> <span class="title">Enumerable</span> <span class="title">do</span></span></span><br><span class="line">./<span class="class"><span class="keyword">lib</span>/<span class="title">elixir</span>/<span class="title">lib</span>/<span class="title">range</span>.<span class="title">ex</span>:66:<span class="title">defimpl</span> <span class="title">Enumerable</span>, <span class="title">for</span>: <span class="title">Range</span> <span class="title">do</span></span></span><br><span class="line">./<span class="class"><span class="keyword">lib</span>/<span class="title">elixir</span>/<span class="title">lib</span>/<span class="title">stream</span>.<span class="title">ex</span>:1222:<span class="title">defimpl</span> <span class="title">Enumerable</span>, <span class="title">for</span>: <span class="title">Stream</span> <span class="title">do</span></span></span><br></pre></td></tr></table></figure><p>That’s great, but maybe not so practical right now. Let’s focus on the <strong>lazy</strong> property of streams which is what we’ll leverage to paginate on an “as-needed” basis.</p><p>Being lazy, you can define any transformation you want on streams using the API in the <a href="http://elixir-lang.org/docs/v1.2/elixir/Stream.html" target="_blank" rel="external">Stream</a> module, but doing so will <strong>not</strong> trigger the stream’s enumeration. This means that “nothing” will actually happen when you define a stream or make one from another using the Stream module’s API.</p><p>Consider the following (adapted from the <a href="http://elixir-lang.org/docs/v1.2/elixir/Stream.html#map/2" target="_blank" rel="external">online doc</a>):</p><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">iex(<span class="number">1</span>)&gt; stream = <span class="constant">Stream.</span>map([<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>], <span class="keyword">fn</span>(x) -&gt; <span class="constant">IO.</span>puts <span class="string">"x is <span class="subst">#&#123;x&#125;</span>"</span>; x * <span class="number">2</span> <span class="keyword">end</span>)</span><br><span class="line"><span class="comment">#Stream&lt;[enum: [1, 2, 3], funs: [#Function&lt;44.120526864/1 in Stream.map/2&gt;]]&gt;</span></span><br><span class="line">iex(<span class="number">2</span>)&gt; <span class="constant">Enum.</span>to_list(stream)</span><br><span class="line">x is <span class="number">1</span></span><br><span class="line">x is <span class="number">2</span></span><br><span class="line">x is <span class="number">3</span></span><br><span class="line">[<span class="number">2</span>, <span class="number">4</span>, <span class="number">6</span>]</span><br></pre></td></tr></table></figure><p>In our first expression (<code>iex(1)&gt;</code>), we are creating a stream from a list and a function, using <a href="http://elixir-lang.org/docs/v1.2/elixir/Stream.html#map/2" target="_blank" rel="external">Stream.map/2</a>. The REPL shows us that we got back a stream from <code>Stream.map/2</code>. It shows us a human readable string <a href="https://github.com/elixir-lang/elixir/blob/v1.2/lib/elixir/lib/stream.ex#L1268-L1274" target="_blank" rel="external">based on</a> the <a href="http://elixir-lang.org/docs/v1.2/elixir/Inspect.html" target="_blank" rel="external">Inspect</a> protocol. As a side note:</p><blockquote>Keep in mind that, by convention, whenever the inspected value starts with #, it is representing a data structure in non-valid Elixir syntax.<footer><cite><a href="http://elixir-lang.org/getting-started/protocols.html" target="_blank" rel="external">Protocols</a></cite></footer></blockquote><p>In other words, the <code>stream</code> variable is now bound to a stream - “some kind of data structure” - the innards of which you should make no assumptions on (as they <em>might</em> change in different versions of Elixir).</p><p>In our second expression (<code>iex(2)&gt;</code>), we’re using <a href="http://elixir-lang.org/docs/v1.1/elixir/Enum.html#to_list/1" target="_blank" rel="external">Enum.to_list/1</a> to convert the stream data structure to an Erlang/Elixir list. On doing so, <code>to_list/1</code> is internally calling <a href="http://elixir-lang.org/docs/v1.2/elixir/Enumerable.html#reduce/3" target="_blank" rel="external">Enumerable.reduce/3</a> on the stream we pass to it which will “force” the lazy stream to produce something. In the case of <code>to_list/1</code>, the stream is “forced” to keep producing values until it’s exhausted.</p><p>That is why we don’t see the side effect of printing to stdout until we actually trigger the stream’s enumeration.</p><p>Of course, we don’t <em>have</em> to exhaust the stream. We can just take what we want from it, e.g. using <a href="http://elixir-lang.org/docs/v1.1/elixir/Enum.html#take/2" target="_blank" rel="external">Enum.take/2</a>:</p><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">iex(<span class="number">3</span>)&gt; <span class="constant">Enum.</span>take(stream, <span class="number">1</span>)</span><br><span class="line">x is <span class="number">1</span></span><br><span class="line">[<span class="number">2</span>]</span><br></pre></td></tr></table></figure><p>But consider this:</p><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">iex(<span class="number">4</span>)&gt; <span class="constant">Enum.</span>take([<span class="number">4</span>, <span class="number">5</span>, <span class="number">6</span>], <span class="number">1</span>)</span><br><span class="line">[<span class="number">4</span>]</span><br></pre></td></tr></table></figure><p>What’s different here? The difference is that the data you <code>take/2</code> from <code>stream</code> doesn’t actually exist until you take it, whereas that from <code>[4, 5, 6]</code> exists in memory before ever calling <code>take/2</code> on it. Granted, in this case, <code>stream</code> is lazily producing data from a list data source which exists in memory (i.e. <code>[1, 2, 3]</code>). This might make the distinction a little more nuanced for this particular example, but what’s important to keep in mind is that the actual values the <code>stream</code> produces (<code>1</code>, <code>2</code>, and <code>3</code>) <em>don’t exist</em> in memory until the stream is actually consumed. Our <code>stream</code> could just as easily be feeding our program data from a database or a REST API instead of an in-memory data structure.</p><p>For example, it could be giving <code>Enum.take/2</code> data it got from its first HTTP request to Github’s REST API. If <code>take/2</code> doesn’t want more than 30 repos, then <code>stream</code> only ever needs to make 1 HTTP request. If <code>take/2</code> wants more, <code>stream</code> would have to paginate as necessary but at least <code>take/2</code> doesn’t have to wait until <code>stream</code> makes enough requests to exhaust the number of repos for a particular organization before it starts receiving data from <code>stream</code>.</p><p>That is exactly what we want for the Elixir API we’ll be writing.</p><p>But first…</p><h1 id="Know-your-poison"><a href="#Know-your-poison" class="headerlink" title="Know your poison"></a>Know your poison</h1><p>The example coming up next makes use of <a href="https://github.com/edgurgel/httpoison" target="_blank" rel="external">HTTPoison</a> as well as the more mainstream (but no less deadly) <a href="https://github.com/devinus/poison" target="_blank" rel="external">Poison</a> modules - so it makes sense to cover basic usage of each before digging in.</p><p>Bootstrap a new project with <code>mix new github</code>; <code>cd</code> into it, and add these modules as dependencies in <code>mix.exs</code>:</p><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">defp</span> <span class="title">deps</span></span> <span class="keyword">do</span></span><br><span class="line">  [&#123;<span class="symbol">:httpoison</span>, <span class="string">"~&gt; 0.8.0"</span>&#125;, &#123;<span class="symbol">:poison</span>, <span class="string">"~&gt; 1.5"</span>&#125;]</span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p>Then run <code>mix deps.get</code> to fetch the poisonous bunch.</p><h2 id="HTTPoison"><a href="#HTTPoison" class="headerlink" title="HTTPoison"></a>HTTPoison</h2><p>First things first. Unless you fancy manually starting the HTTPoison applicaiton every time you load <code>iex</code> (with <code>HTTPoison.start</code>), add it as an application in mix.exs:</p><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">application</span></span> <span class="keyword">do</span></span><br><span class="line">  [<span class="symbol">applications:</span> [<span class="symbol">:logger</span>, <span class="symbol">:httpoison</span>]]</span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p>It seems that some processes need to be running before using HTTPoison and adding <code>:httpoison</code> in the <code>applications</code> <a href="http://elixir-lang.org/getting-started/maps-and-dicts.html#keyword-lists" target="_blank" rel="external">keyword list</a> will automatically make this happen. I’m guessing that modules listed in <code>applications</code> have their <a href="https://github.com/edgurgel/httpoison/blob/v0.8.0/lib/httpoison/base.ex#L81" target="_blank" rel="external">start</a> function called by <a href="https://github.com/elixir-lang/elixir/tree/master/lib/mix" target="_blank" rel="external">mix</a> which then spawn the processes, but I’m not entirely sure how that works.</p><p>In HTTPoison’s case, Erlang’s <a href="http://www.erlang.org/doc/apps/kernel/application.html#ensure_started-1" target="_blank" rel="external">application:ensure_all_started/1</a> seems to be what’s making this happen.</p><p>In any case, starting iex and loading our app with <a href="https://github.com/elixir-lang/elixir/wiki/FAQ#3-how-do-i-start-a-shell-iex-with-my-project-and-all-its-dependencies-loaded-and-started" target="_blank" rel="external">iex -S mix</a> (which starts a shell with the project and all of its dependencies loaded and started), we can now start experimenting a bit:</p><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">iex(<span class="number">1</span>)&gt; <span class="constant">HTTPoison.</span>get! <span class="string">"https://api.github.com/orgs/elixir-lang/repos"</span></span><br><span class="line"><span class="comment"># ...</span></span><br></pre></td></tr></table></figure><p>should give you back a bunch of data with a status code of 200. From the example request in the project’s <a href="https://github.com/edgurgel/httpoison" target="_blank" rel="external">README.md</a> (and from <a href="https://github.com/edgurgel/httpoison/blob/v0.8.0/lib/httpoison.ex#L2" target="_blank" rel="external">this</a>), we can see that the response we get back is a <code>HTTPoison.Response</code> <a href="http://elixir-lang.org/getting-started/structs.html" target="_blank" rel="external">struct</a> with an integer <code>status_code</code>, a binary <code>body</code>, and a list for <code>headers</code>:</p><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">iex(<span class="number">2</span>)&gt; %<span class="constant">HTTPoison.Response&#123;</span><span class="symbol">body:</span> body, <span class="symbol">headers:</span> headers, <span class="symbol">status_code:</span> status_code&#125; = v(<span class="number">1</span>)</span><br><span class="line"><span class="comment"># ...</span></span><br></pre></td></tr></table></figure><p>Above, we’re getting the evaluation of expression 1 in iex (i.e. the result of <code>iex(1)&gt;</code>) and extracting its individual parts using <a href="http://elixir-lang.org/getting-started/pattern-matching.html" target="_blank" rel="external">pattern matching</a> (we’re using the <a href="http://elixir-lang.org/docs/master/iex/IEx.Helpers.html#v/1" target="_blank" rel="external">v(n \\ -1)</a> iex helper function to do this - and note that the double backslash syntax in the helper function’s doc is for <a href="http://elixir-lang.org/getting-started/modules.html#default-arguments" target="_blank" rel="external">default arguments</a>). We now have the following bound variables in our iex session: <code>body</code>, <code>headers</code>, and <code>status_code</code>.</p><p>Next, add <code>lib/github_gateway.ex</code>:</p><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># lib/github_gateway.ex</span></span><br><span class="line"><span class="class"><span class="keyword">defmodule</span> <span class="title">Github</span></span>.<span class="constant">Gateway </span><span class="keyword">do</span></span><br><span class="line">  <span class="keyword">use</span> <span class="constant">HTTPoison.Base</span></span><br><span class="line"></span><br><span class="line">  <span class="variable">@endpoint</span> <span class="string">"https://api.github.com"</span></span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">def</span> <span class="title">endpoint</span></span> <span class="keyword">do</span></span><br><span class="line">    <span class="variable">@endpoint</span></span><br><span class="line">  <span class="keyword">end</span></span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">defp</span> <span class="title">process_url</span></span>(url) <span class="keyword">do</span></span><br><span class="line">    <span class="variable">@endpoint</span> &lt;&gt; url</span><br><span class="line">  <span class="keyword">end</span></span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p>There’s a couple of things to note here. The easiest to explain is the definition of the <code>@endpoint</code> <a href="http://elixir-lang.org/getting-started/module-attributes.html#as-constants" target="_blank" rel="external">module attribute</a> which serves as a constant. At compile time, usage of this attribute is changed to the Github endpoint we’ve set it to.</p><p>We’re also using <code>use HTTPoison.Base</code>, and as we can see from the <a href="http://elixir-lang.org/getting-started/alias-require-and-import.html#use" target="_blank" rel="external">online doc</a>, this is compiled to something like:</p><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">defmodule</span> <span class="title">Github</span></span>.<span class="constant">Gateway </span><span class="keyword">do</span></span><br><span class="line">  require <span class="constant">HTTPoison.Base</span></span><br><span class="line">  <span class="constant">HTTPoison.Base.__using__ </span>[]</span><br><span class="line">  <span class="comment"># ...</span></span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><blockquote>Behind the scenes, <code>use</code> requires the given module and then calls the <code>__using__/1</code> callback on it allowing the module to inject some code into the current context.<footer><cite><a href="http://elixir-lang.org/getting-started/alias-require-and-import.html#use" target="_blank" rel="external">Getting started guide</a></cite></footer></blockquote><p>(note: I’m passing <code>__using__/1</code> an empty list as an argument above. This list is an empty <a href="http://elixir-lang.org/getting-started/maps-and-dicts.html#keyword-lists" target="_blank" rel="external">keyword list</a>, which means that if it weren’t empty (i.e. if we had passed any options to the module we were <code>use</code>ing), they would be present in this list when the <code>use</code> macro is expanded in the form of 2-element tuples with an atom for the first element).</p><p><code>require</code>ing seems to be necessary to “guarantee” that <code>HTTPoison.Base</code> is available during compilation:</p><blockquote>Macros are chunks of code that are executed and expanded at compilation time. This means, in order to use a macro, we need to guarantee its module and implementation are available during compilation. This is done with the <code>require</code> directive<footer><cite><a href="http://elixir-lang.org/getting-started/alias-require-and-import.html#require" target="_blank" rel="external">Getting started guide</a></cite></footer></blockquote><p>However, when the compiler is processing this, “code injection” (or “macro expansion”) isn’t over after just the first step above (the expansion of the <code>use</code> macro) because <a href="https://github.com/edgurgel/httpoison/blob/v0.8.0/lib/httpoison/base.ex#L74" target="_blank" rel="external">HTTPoison.Base.__using__/1</a> is itself a macro, so it needs to be expanded too.</p><p>If you have just a quick look at <a href="https://github.com/edgurgel/httpoison/blob/v0.8.0/lib/httpoison/base.ex#L74" target="_blank" rel="external">HTTPoison.Base.__using__/1</a>, you’ll see that it’s defining a bunch of functions within a <a href="http://elixir-lang.org/getting-started/meta/quote-and-unquote.html#quoting" target="_blank" rel="external">quote</a> block. Basically, we can write normal Elixir code within <code>quote</code> blocks and all that code will be transformed into a data structure which is understood by, and fed to, the Elixir compiler during macro expansion.</p><p>Effectively, it’s as if the functions in this <code>quote</code> block were defined in our module, <code>Github.Gateway</code>.</p><p>You can confirm this by removing the <code>use HTTPoison.Base</code> expression in <code>Github.Gateway</code> (or replacing <code>use</code> with <code>require</code> without calling the <code>__using__/1</code> macro). If you then <code>iex -S mix</code> and hit the <code>&lt;TAB&gt;</code> key after <code>Github.Gateway.</code>, it will expand to the only thing available in that module at this point, the public <code>endpoint</code> function. If you <code>use HTTPoison.Base</code> and try the same thing, you’ll get a list of the injected code:</p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">iex(1)&gt; Github.Gateway.</span><br><span class="line">delete!/3     delete/3      endpoint/0    get!/3        get/3</span><br><span class="line">head!/3       head/3        options!/3    options/3     patch!/4</span><br><span class="line">patch/4       post!/4       post/4        put!/4        put/4</span><br><span class="line">request!/5    request/5     start/0</span><br></pre></td></tr></table></figure><p>As you can see, we now have <a href="https://github.com/edgurgel/httpoison/blob/v0.8.0/lib/httpoison/base.ex#L194" target="_blank" rel="external">get!/3</a>, the same function we used from <code>HTTPoison</code> just a minute ago. <a href="https://github.com/edgurgel/httpoison/blob/v0.8.0/lib/httpoison.ex#L44-L67" target="_blank" rel="external">In fact</a>:</p><blockquote>Under the hood, the <a href="http://hexdocs.pm/httpoison/HTTPoison.html#content" target="_blank" rel="external">HTTPoison</a> module just uses <a href="http://hexdocs.pm/httpoison/HTTPoison.Base.html" target="_blank" rel="external">HTTPoison.Base</a>… without overriding any default function.<footer><cite><a href="http://hexdocs.pm/httpoison/HTTPoison.html#content" target="_blank" rel="external">HTTPoison docs</a></cite></footer></blockquote><p>However, since we’ve defined our own <code>process_url/1</code> function, we don’t need to specify the full URL to make a similar request to the one we’ve made before:</p><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">iex(<span class="number">1</span>)&gt; <span class="constant">Github.Gateway.</span>get! <span class="string">"/orgs/elixir-lang/repos"</span></span><br><span class="line"><span class="comment"># ...</span></span><br></pre></td></tr></table></figure><p>In fact, we <em>can’t</em> specify the full URL as a parameter since we’ve changed the <a href="https://github.com/edgurgel/httpoison/blob/v0.8.0/lib/httpoison/base.ex#L83-L85" target="_blank" rel="external">default</a> <a href="https://github.com/edgurgel/httpoison/blob/v0.8.0/lib/httpoison/base.ex#L354-L361" target="_blank" rel="external">implementation</a> of <code>process_url/1</code> to:</p><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">defp</span> <span class="title">process_url</span></span>(url) <span class="keyword">do</span></span><br><span class="line">  <span class="variable">@endpoint</span> &lt;&gt; url</span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p>and we’d have an invalid URL if we did.</p><p>The HTTPoison documentation is clear about this “overriding” feature:</p><blockquote>HTTPoison.Base defines the following list of functions, all of which can be overridden (by redefining them)…<footer><cite><a href="http://hexdocs.pm/httpoison/HTTPoison.Base.html" target="_blank" rel="external">HTTPoison.Base docs</a></cite></footer></blockquote><p>OK… but it’s not like this is <a href="https://en.wikipedia.org/wiki/Object-oriented_programming" target="_blank" rel="external">OOP</a> and looking into <code>use</code>ing a module doesn’t explain anything about function overriding. So how does this work?</p><p>To better understand what’s going on, we need to dig a bit deeper. We know that <code>HTTPoison.Base.__using__/1</code> macro is expanded at compile time when <code>use</code>ing <code>HTTPoison.Base</code>, and if we look into it, we come across this <a href="https://github.com/edgurgel/httpoison/blob/v0.8.0/lib/httpoison/base.ex#L329" target="_blank" rel="external">line</a> in the macro’s definition:</p><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">defoverridable <span class="constant">Module.</span>definitions_in(<span class="constant">__MODULE__)</span></span><br></pre></td></tr></table></figure><p><a href="https://github.com/elixir-lang/elixir/blob/v1.2/lib/elixir/lib/module.ex#L731-L746" target="_blank" rel="external">Module.definitions_in/1</a> is being passed the <a href="http://elixir-lang.org/docs/v1.2/elixir/Kernel.SpecialForms.html#__MODULE__/0" target="_blank" rel="external">__MODULE__/0</a> pseudo variable, the evaluation of which seems to be listing all functions defined in <code>HTTPoison.Base</code>.</p><blockquote>Pseudo variables return information about Elixir’s compilation environment and can only be read, never assigned to.<footer><cite><a href="http://elixir-lang.org/docs/v1.2/elixir/Kernel.SpecialForms.html" target="_blank" rel="external">Pseudo variables</a></cite></footer></blockquote><p>If we now take a look at the <a href="https://github.com/elixir-lang/elixir/blob/v1.2/lib/elixir/lib/kernel.ex#L3501-L3537" target="_blank" rel="external">Kernel.defoverridable/1</a> macro, we’ll find out that this is what’s responsible for the overridability feature:</p><blockquote>Makes the given functions in the current module overridable.<br>An overridable function is lazily defined, allowing a developer to override it.<footer><cite><a href="https://github.com/elixir-lang/elixir/blob/v1.2/lib/elixir/lib/kernel.ex#L3501-L3537" target="_blank" rel="external">Kernel.defoverridable/1 doc</a></cite></footer></blockquote><p>It’s also interesting to note the example which comes with the doc for that macro:</p><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">defmodule</span> <span class="title">DefaultMod</span></span> <span class="keyword">do</span></span><br><span class="line">  <span class="function"><span class="keyword">defmacro</span> <span class="title">__using__</span></span>(<span class="constant">_opts)</span> <span class="keyword">do</span></span><br><span class="line">    <span class="keyword">quote</span> <span class="keyword">do</span></span><br><span class="line">      <span class="function"><span class="keyword">def</span> <span class="title">test</span></span>(x, y) <span class="keyword">do</span></span><br><span class="line">        x + y</span><br><span class="line">      <span class="keyword">end</span></span><br><span class="line">      defoverridable [<span class="symbol">test:</span> <span class="number">2</span>]</span><br><span class="line">    <span class="keyword">end</span></span><br><span class="line">  <span class="keyword">end</span></span><br><span class="line"><span class="keyword">end</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">defmodule</span> <span class="title">InheritMod</span></span> <span class="keyword">do</span></span><br><span class="line">  <span class="keyword">use</span> <span class="constant">DefaultMod</span></span><br><span class="line">  <span class="function"><span class="keyword">def</span> <span class="title">test</span></span>(x, y) <span class="keyword">do</span></span><br><span class="line">    x * y + super(x, y)</span><br><span class="line">  <span class="keyword">end</span></span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p>Apart from noticing that <code>defoverridable/1</code> takes a <a href="http://elixir-lang.org/getting-started/maps-and-dicts.html#keyword-lists" target="_blank" rel="external">keyword list</a> as an argument, implying that <code>Module.definitions_in/1</code> returns a keyword list, we can see usage of <code>super</code> to call the default implementation of <code>test</code> in the example.</p><p>Lets see this <code>super</code> call in action by using it in our <code>process_url/1</code>:</p><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">defp</span> <span class="title">process_url</span></span>(url) <span class="keyword">do</span></span><br><span class="line">  <span class="keyword">case</span> url |&gt; <span class="constant">String.</span>slice(<span class="number">0</span>, <span class="number">8</span>) |&gt; <span class="constant">String.</span>downcase <span class="keyword">do</span></span><br><span class="line">    <span class="string">"http://"</span> &lt;&gt; <span class="constant">_ </span>-&gt; super url</span><br><span class="line">    <span class="string">"https://"</span> &lt;&gt; <span class="constant">_ </span>-&gt; super url</span><br><span class="line">    <span class="constant">_ </span>-&gt; <span class="variable">@endpoint</span> &lt;&gt; url</span><br><span class="line">  <span class="keyword">end</span></span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p>(Read up on the use of the pipe operator, <a href="http://elixir-lang.org/docs/v1.2/elixir/Kernel.html#%7C%3E/2" target="_blank" rel="external">|&gt;</a>, if you’re not familiar with it). Now, both of the following will give us a <code>200</code> status code:</p><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">iex(<span class="number">1</span>)&gt; <span class="constant">Github.Gateway.</span>get! <span class="string">"https://api.github.com/orgs/elixir-lang/repos"</span></span><br><span class="line"><span class="comment"># ...</span></span><br><span class="line">iex(<span class="number">2</span>)&gt; <span class="constant">Github.Gateway.</span>get! <span class="string">"/orgs/elixir-lang/repos"</span></span><br><span class="line"><span class="comment"># ...</span></span><br></pre></td></tr></table></figure><p>Of course, the same prefix check is happening in <a href="https://github.com/edgurgel/httpoison/blob/v0.8.0/lib/httpoison/base.ex#L354-L361" target="_blank" rel="external">super</a> in this case, but the point is it works as expected.</p><h2 id="Poison"><a href="#Poison" class="headerlink" title="Poison"></a>Poison</h2><p>Moving on to <a href="http://www.json.org/" target="_blank" rel="external">JSON</a> parsing with <a href="https://github.com/devinus/poison" target="_blank" rel="external">Poison</a>. We’re already depending on it so if we <code>iex -S mix</code>, we can start exploring its basic usage (and how to get to specific bits of data):</p><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line">iex(<span class="number">1</span>)&gt; %<span class="constant">HTTPoison.Response&#123;</span> <span class="symbol">body:</span> body &#125; = <span class="constant">Github.Gateway.</span>get! <span class="string">"/orgs/elixir-lang/repos"</span></span><br><span class="line"><span class="comment"># ...</span></span><br><span class="line">iex(<span class="number">2</span>)&gt; i body</span><br><span class="line"><span class="comment"># ...</span></span><br><span class="line"><span class="constant">Data </span>type</span><br><span class="line">  <span class="constant">BitString</span></span><br><span class="line"><span class="constant">Byte </span>size</span><br><span class="line">  <span class="number">58284</span></span><br><span class="line"><span class="constant">Description</span></span><br><span class="line">  <span class="constant">This </span>is a <span class="symbol">string:</span> a <span class="constant">UTF-</span><span class="number">8</span> encoded binary. <span class="constant">It'</span>s printed surrounded by</span><br><span class="line">  <span class="string">"double quotes"</span> because all <span class="constant">UTF-</span><span class="number">8</span> encoded codepoints <span class="keyword">in</span> it are printable.</span><br><span class="line">iex(<span class="number">3</span>)&gt; parsed_body = <span class="constant">Poison.Parser.</span>parse! body</span><br><span class="line"><span class="comment"># ...</span></span><br><span class="line">iex(<span class="number">4</span>)&gt; i parsed_body</span><br><span class="line"><span class="comment"># ...</span></span><br><span class="line"><span class="constant">Data </span>type</span><br><span class="line">  <span class="constant">List</span></span><br><span class="line">iex(<span class="number">5</span>)&gt; length parsed_body</span><br><span class="line"><span class="number">12</span></span><br><span class="line">iex(<span class="number">6</span>)&gt; parsed_body |&gt; <span class="constant">List.</span>first |&gt; <span class="constant">Map.</span>get(<span class="string">"name"</span>)</span><br><span class="line"><span class="string">"elixir"</span></span><br><span class="line">iex(<span class="number">7</span>)&gt; <span class="symbol">:lists</span>.nth(<span class="number">4</span>, parsed_body)[<span class="string">"name"</span>]</span><br><span class="line"><span class="string">"ex_doc"</span></span><br><span class="line">iex(<span class="number">8</span>)&gt; elixir_repo = parsed_body |&gt; <span class="constant">Enum.</span>at(<span class="number">0</span>)</span><br><span class="line"><span class="comment"># ...</span></span><br><span class="line">iex(<span class="number">9</span>)&gt; i elixir_repo</span><br><span class="line"><span class="comment"># ...</span></span><br><span class="line"><span class="constant">Data </span>type</span><br><span class="line">  <span class="constant">Map</span></span><br><span class="line">iex(<span class="number">10</span>)&gt; elixir_repo[<span class="string">"full_name"</span>]</span><br><span class="line"><span class="string">"elixir-lang/elixir"</span></span><br><span class="line">iex(<span class="number">11</span>)&gt; [<span class="constant">_,</span> <span class="constant">_,</span> <span class="constant">_,</span> %&#123; <span class="string">"full_name"</span> =&gt; ex_doc_repo_full_name &#125; | <span class="constant">_]</span> = parsed_body</span><br><span class="line"><span class="comment"># ...</span></span><br><span class="line">iex(<span class="number">12</span>)&gt; ex_doc_repo_full_name</span><br><span class="line"><span class="string">"elixir-lang/ex_doc"</span></span><br></pre></td></tr></table></figure><p>I’m digressing a bit here to show off different ways in which you can manipulate the parsed data:</p><ul><li><code>iex(1)</code> is old news by now, we’ve already seen that we can do this to get the body of our HTTP request.</li><li><code>iex(2)</code> is using the <a href="http://elixir-lang.org/docs/v1.2/iex/IEx.Helpers.html#i/1" target="_blank" rel="external">i iex helper function</a> which shows us that <code>body</code> is a BitString.</li><li><code>iex(3)</code> is parsing the <code>body</code> with <a href="https://github.com/devinus/poison/blob/1.5.2/lib/poison/parser.ex#L48-L58" target="_blank" rel="external">Poison.Parser.parse!/2</a> and binding the result to <code>parsed_body</code>. Note: For more info on variable naming conventions and the significance of the “trailing bang” in <code>Poison.Parser.parse!</code>, you can read up on these in the <a href="http://elixir-lang.org/docs/master/elixir/naming-conventions.html" target="_blank" rel="external">online doc for naming conventions</a>.</li><li><code>iex(5)</code> shows us the length of <code>parsed_body</code> List via the built-in (i.e. imported by default in your modules and <a href="https://github.com/elixir-lang/elixir/blob/v1.2.0/lib/elixir/lib/kernel.ex#L440-L454" target="_blank" rel="external">defined in the Kernel module</a>) <a href="http://elixir-lang.org/docs/v1.2/elixir/Kernel.html#length/1" target="_blank" rel="external">length</a> function.</li><li><code>iex(6)</code> is piping to <a href="http://elixir-lang.org/docs/v1.2/elixir/List.html#first/1" target="_blank" rel="external">List.first/1</a> to get the first element in <code>parsed_body</code> and then piping again to <a href="http://elixir-lang.org/docs/v1.2/elixir/Map.html#get/3" target="_blank" rel="external">Map.get/3</a> to get the value for the <code>&quot;name&quot;</code> String key. Note that <code>Map.get/3</code> has an optional 3rd argument (with a default value) and <a href="http://elixir-lang.org/docs/v1.2/elixir/Kernel.html#%7C%3E/2" target="_blank" rel="external">|&gt;</a> is supplying the first argument.</li><li><code>iex(7)</code> is similarly getting the value for the <code>&quot;name&quot;</code> String key in the 4th element in <code>parsed_body</code> using <a href="http://www.erlang.org/doc/man/lists.html#nth-2" target="_blank" rel="external">Erlang’s lists:nth/2</a> function. Note that we cannot pipe <code>parsed_body</code> into this function as it takes the index for its first argument (as opposed to the List). Also note that the index for <code>lists:nth/2</code> starts from 1 not 0.</li><li><code>iex(8)</code> demonstrates another way of picking elements from a list using <a href="http://elixir-lang.org/docs/v1.2/elixir/Enum.html#at/3" target="_blank" rel="external">Enum.at/3</a>.</li><li><code>iex(11)</code> uses <a href="http://elixir-lang.org/getting-started/pattern-matching.html" target="_blank" rel="external">pattern matching</a> to get to the value of the <code>&quot;full_name&quot;</code> key in the Map which is the 4th element in the <code>parsed_body</code> List.</li></ul><p>So we’ve parsed some JSON into a list of maps and singled out bits of data from it. We’re now ready to write that data back out, or “encode” it back to JSON:</p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">iex(13)&gt; Poison.encode(elixir_repo)</span><br><span class="line">&#123;:ok,</span><br><span class="line">"&#123;\"teams_url\":\"https://api.github.com/repos/elixir-lang/elixir/teams\",</span><br><span class="line"># ...</span><br><span class="line">iex(14)&gt; elem(Poison.encode(elixir_repo), 1)</span><br><span class="line">"&#123;\"teams_url\":\"https://api.github.com/repos/elixir-lang/elixir/teams\",</span><br><span class="line"># ...</span><br><span class="line">iex(15)&gt; IO.puts elem(Poison.encode(elixir_repo), 1)</span><br><span class="line">&#123;"teams_url":"https://api.github.com/repos/elixir-lang/elixir/teams",</span><br><span class="line"># ...</span><br><span class="line">iex(16)&gt; IO.puts elem(Poison.encode(elixir_repo, [pretty: 2]), 1)</span><br><span class="line">&#123;</span><br><span class="line">  "teams_url": "https://api.github.com/repos/elixir-lang/elixir/teams",</span><br><span class="line">  "branches_url": "https://api.github.com/repos/elixir-lang/elixir/branches&#123;/branch&#125;",</span><br><span class="line"># ...</span><br><span class="line">iex(17)&gt; File.write("./elixir_repo.json", elem(Poison.encode(elixir_repo, [pretty: 2]), 1))</span><br><span class="line">:ok</span><br><span class="line">iex(18)&gt; elixir_repo |&gt; Poison.encode([pretty: 2]) |&gt; elem(1) |&gt; IO.puts</span><br><span class="line"># ... same as iex(16)</span><br></pre></td></tr></table></figure><ul><li><code>iex(13)</code> uses <a href="https://github.com/devinus/poison/blob/master/lib/poison.ex#L6-L19" target="_blank" rel="external">Poison.encode/2</a> without <code>options</code> (thus defaulting to an empty List) to encode the <code>elixir_repo</code> Map to JSON. This returns a tuple with <code>:ok</code> as the first element and the encoded JSON as the second.</li><li><code>iex(14)</code> uses <a href="http://elixir-lang.org/docs/v1.2/elixir/Kernel.html#elem/2" target="_blank" rel="external">elem/2</a> to extract the JSON from the tuple.</li><li><code>iex(15)</code> prints <code>iex(14)</code> to stdout.</li><li><code>iex(16)</code> uses the <code>[pretty: 2]</code> <a href="https://github.com/devinus/poison/blob/1.5.2/lib/poison/encoder.ex#L31-L60" target="_blank" rel="external">option</a> when encoding to print the JSON in a more readable fashion.</li><li><code>iex(17)</code> does the same thing but writes to the <code>&quot;./elixir_repo.json&quot;</code> file instead of stdout.</li><li><code>iex(18)</code> is just <code>iex(16)</code> using pipes.</li></ul><p>While we’re at it, and since we have a large enough Map to demo it, consider the following:</p><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line">iex(<span class="number">19</span>)&gt; <span class="constant">Map.</span>keys elixir_repo</span><br><span class="line">[<span class="string">"statuses_url"</span>, <span class="string">"git_refs_url"</span>, <span class="string">"issue_comment_url"</span>, <span class="string">"watchers"</span>, <span class="string">"mirror_url"</span>,</span><br><span class="line"> <span class="string">"languages_url"</span>, <span class="string">"stargazers_count"</span>, <span class="string">"forks"</span>, <span class="string">"default_branch"</span>, <span class="string">"comments_url"</span>,</span><br><span class="line"> <span class="string">"commits_url"</span>, <span class="string">"id"</span>, <span class="string">"clone_url"</span>, <span class="string">"homepage"</span>, <span class="string">"stargazers_url"</span>, <span class="string">"events_url"</span>,</span><br><span class="line"> <span class="string">"blobs_url"</span>, <span class="string">"forks_count"</span>, <span class="string">"pushed_at"</span>, <span class="string">"git_url"</span>, <span class="string">"hooks_url"</span>, <span class="string">"owner"</span>,</span><br><span class="line"> <span class="string">"trees_url"</span>, <span class="string">"git_commits_url"</span>, <span class="string">"collaborators_url"</span>, <span class="string">"watchers_count"</span>,</span><br><span class="line"> <span class="string">"tags_url"</span>, <span class="string">"merges_url"</span>, <span class="string">"releases_url"</span>, <span class="string">"subscribers_url"</span>, <span class="string">"ssh_url"</span>,</span><br><span class="line"> <span class="string">"created_at"</span>, <span class="string">"name"</span>, <span class="string">"has_issues"</span>, <span class="string">"private"</span>, <span class="string">"git_tags_url"</span>, <span class="string">"archive_url"</span>,</span><br><span class="line"> <span class="string">"has_wiki"</span>, <span class="string">"open_issues_count"</span>, <span class="string">"milestones_url"</span>, <span class="string">"forks_url"</span>, <span class="string">"url"</span>,</span><br><span class="line"> <span class="string">"downloads_url"</span>, <span class="string">"open_issues"</span>, <span class="string">"keys_url"</span>, <span class="string">"description"</span>, <span class="string">"contents_url"</span>,</span><br><span class="line"> <span class="string">"language"</span>, <span class="string">"permissions"</span>, <span class="string">"contributors_url"</span>, ...]</span><br><span class="line">iex(<span class="number">20</span>)&gt; elixir_repo |&gt; <span class="constant">Map.</span>keys |&gt; length</span><br><span class="line"><span class="number">68</span></span><br><span class="line">iex(<span class="number">21</span>)&gt; <span class="constant">Inspect.Opts.__struct__</span></span><br><span class="line">%<span class="constant">Inspect.Opts&#123;</span><span class="symbol">base:</span> <span class="symbol">:decimal</span>, <span class="symbol">binaries:</span> <span class="symbol">:infer</span>, <span class="symbol">char_lists:</span> <span class="symbol">:infer</span>, <span class="symbol">limit:</span> <span class="number">50</span>,</span><br><span class="line"> <span class="symbol">pretty:</span> <span class="keyword">false</span>, <span class="symbol">safe:</span> <span class="keyword">true</span>, <span class="symbol">structs:</span> <span class="keyword">true</span>, <span class="symbol">width:</span> <span class="number">80</span>&#125;</span><br><span class="line">iex(<span class="number">22</span>)&gt; <span class="constant">Inspect.Opts.__struct__.</span>limit</span><br><span class="line"><span class="number">50</span></span><br><span class="line">iex(<span class="number">23</span>)&gt; elixir_repo |&gt; <span class="constant">Map.</span>keys |&gt; <span class="constant">Enum.</span>take(<span class="number">50</span>)</span><br><span class="line">[<span class="string">"statuses_url"</span>, <span class="string">"git_refs_url"</span>, <span class="string">"issue_comment_url"</span>, <span class="string">"watchers"</span>, <span class="string">"mirror_url"</span>,</span><br><span class="line"> <span class="string">"languages_url"</span>, <span class="string">"stargazers_count"</span>, <span class="string">"forks"</span>, <span class="string">"default_branch"</span>, <span class="string">"comments_url"</span>,</span><br><span class="line"> <span class="string">"commits_url"</span>, <span class="string">"id"</span>, <span class="string">"clone_url"</span>, <span class="string">"homepage"</span>, <span class="string">"stargazers_url"</span>, <span class="string">"events_url"</span>,</span><br><span class="line"> <span class="string">"blobs_url"</span>, <span class="string">"forks_count"</span>, <span class="string">"pushed_at"</span>, <span class="string">"git_url"</span>, <span class="string">"hooks_url"</span>, <span class="string">"owner"</span>,</span><br><span class="line"> <span class="string">"trees_url"</span>, <span class="string">"git_commits_url"</span>, <span class="string">"collaborators_url"</span>, <span class="string">"watchers_count"</span>,</span><br><span class="line"> <span class="string">"tags_url"</span>, <span class="string">"merges_url"</span>, <span class="string">"releases_url"</span>, <span class="string">"subscribers_url"</span>, <span class="string">"ssh_url"</span>,</span><br><span class="line"> <span class="string">"created_at"</span>, <span class="string">"name"</span>, <span class="string">"has_issues"</span>, <span class="string">"private"</span>, <span class="string">"git_tags_url"</span>, <span class="string">"archive_url"</span>,</span><br><span class="line"> <span class="string">"has_wiki"</span>, <span class="string">"open_issues_count"</span>, <span class="string">"milestones_url"</span>, <span class="string">"forks_url"</span>, <span class="string">"url"</span>,</span><br><span class="line"> <span class="string">"downloads_url"</span>, <span class="string">"open_issues"</span>, <span class="string">"keys_url"</span>, <span class="string">"description"</span>, <span class="string">"contents_url"</span>,</span><br><span class="line"> <span class="string">"language"</span>, <span class="string">"permissions"</span>, <span class="string">"contributors_url"</span>]</span><br><span class="line">iex(<span class="number">24</span>)&gt; <span class="constant">IEx.</span>configure(<span class="symbol">inspect:</span> [<span class="symbol">limit:</span> <span class="number">70</span>])</span><br><span class="line"><span class="symbol">:ok</span></span><br><span class="line">iex(<span class="number">25</span>)&gt; <span class="constant">Map.</span>keys elixir_repo</span><br><span class="line">[<span class="string">"statuses_url"</span>, <span class="string">"git_refs_url"</span>, <span class="string">"issue_comment_url"</span>, <span class="string">"watchers"</span>, <span class="string">"mirror_url"</span>,</span><br><span class="line"> <span class="string">"languages_url"</span>, <span class="string">"stargazers_count"</span>, <span class="string">"forks"</span>, <span class="string">"default_branch"</span>, <span class="string">"comments_url"</span>,</span><br><span class="line"> <span class="string">"commits_url"</span>, <span class="string">"id"</span>, <span class="string">"clone_url"</span>, <span class="string">"homepage"</span>, <span class="string">"stargazers_url"</span>, <span class="string">"events_url"</span>,</span><br><span class="line"> <span class="string">"blobs_url"</span>, <span class="string">"forks_count"</span>, <span class="string">"pushed_at"</span>, <span class="string">"git_url"</span>, <span class="string">"hooks_url"</span>, <span class="string">"owner"</span>,</span><br><span class="line"> <span class="string">"trees_url"</span>, <span class="string">"git_commits_url"</span>, <span class="string">"collaborators_url"</span>, <span class="string">"watchers_count"</span>,</span><br><span class="line"> <span class="string">"tags_url"</span>, <span class="string">"merges_url"</span>, <span class="string">"releases_url"</span>, <span class="string">"subscribers_url"</span>, <span class="string">"ssh_url"</span>,</span><br><span class="line"> <span class="string">"created_at"</span>, <span class="string">"name"</span>, <span class="string">"has_issues"</span>, <span class="string">"private"</span>, <span class="string">"git_tags_url"</span>, <span class="string">"archive_url"</span>,</span><br><span class="line"> <span class="string">"has_wiki"</span>, <span class="string">"open_issues_count"</span>, <span class="string">"milestones_url"</span>, <span class="string">"forks_url"</span>, <span class="string">"url"</span>,</span><br><span class="line"> <span class="string">"downloads_url"</span>, <span class="string">"open_issues"</span>, <span class="string">"keys_url"</span>, <span class="string">"description"</span>, <span class="string">"contents_url"</span>,</span><br><span class="line"> <span class="string">"language"</span>, <span class="string">"permissions"</span>, <span class="string">"contributors_url"</span>, <span class="string">"pulls_url"</span>, <span class="string">"labels_url"</span>,</span><br><span class="line"> <span class="string">"html_url"</span>, <span class="string">"svn_url"</span>, <span class="string">"issue_events_url"</span>, <span class="string">"notifications_url"</span>,</span><br><span class="line"> <span class="string">"has_downloads"</span>, <span class="string">"compare_url"</span>, <span class="string">"full_name"</span>, <span class="string">"subscription_url"</span>,</span><br><span class="line"> <span class="string">"assignees_url"</span>, <span class="string">"issues_url"</span>, <span class="string">"size"</span>, <span class="string">"has_pages"</span>, <span class="string">"fork"</span>, <span class="string">"updated_at"</span>,</span><br><span class="line"> <span class="string">"branches_url"</span>, <span class="string">"teams_url"</span>]</span><br></pre></td></tr></table></figure><ul><li><code>iex(19)</code> prints out the keys in the <code>elixir_repo</code> Map - but note the trailing ellipsis after the <code>&quot;contributors_url&quot;</code> key, i.e. the shell doesn’t print all the keys since it is configured to print up to a limit of number of elements for certain data types, such as lists in this case.</li><li><code>iex(20)</code> shows us how many keys the <code>elixir_repo</code> Map has (68).</li><li><code>iex(21)</code> shows the current settings of <a href="http://elixir-lang.org/docs/v1.2/elixir/Inspect.Opts.html" target="_blank" rel="external">Inspect.Opts</a> which are used by the shell when inspecting values (and “inspecting values” is used when printing our expression results to the shell - and also, for e.g., when using the <code>i</code> helper).</li><li><code>iex(22)</code> highlights the setting we’re currently interested in, the <code>:limit</code> field:</li></ul><blockquote>:limit - limits the number of items that are printed for tuples, bitstrings, and lists, does not apply to strings nor char lists, defaults to 50.<footer><cite><a href="http://elixir-lang.org/docs/v1.2/elixir/Inspect.Opts.html" target="_blank" rel="external">Inspect.Opts doc</a></cite></footer></blockquote><ul><li><code>iex(23)</code> just shows that if we take 50 from the List of keys, we do indeed end up with all the keys printed in <code>iex(19)</code> (no ellipsis).</li><li><code>iex(24)</code> is setting the inspection limit to 70 (by supplying a <a href="http://elixir-lang.org/getting-started/maps-and-dicts.html#keyword-lists" target="_blank" rel="external">keyword list</a> argument). More specifically, it is setting the IEx configuration for inspection via the <code>:inspect</code> keyword list element, whose value takes yet another keyword list made up of the <a href="http://elixir-lang.org/docs/v1.2/elixir/Inspect.Opts.html" target="_blank" rel="external">Inspect.Opts</a> fields we’ve just seen:</li></ul><blockquote>A keyword list containing inspect options used by the shell when printing results of expression evaluation. Default to pretty formatting with a limit of 50 entries.<br>See <a href="http://elixir-lang.org/docs/v1.2/elixir/Inspect.Opts.html" target="_blank" rel="external">Inspect.Opts</a> for the full list of options.<br><footer><cite><a href="http://elixir-lang.org/docs/stable/iex/IEx.html#configure/1" target="_blank" rel="external">IEx.configure/1 :inspect option</a></cite></footer></blockquote><ul><li><code>iex(25)</code> shows the result of this configuration. We are now able to print out all 68 keys.</li></ul><p>You might want to read <a href="http://elixir-lang.org/docs/stable/iex/IEx.html" target="_blank" rel="external">The .iex.exs file</a> section in the IEx docs if you’re interested in setting IEx configuration on shell startup (or just setting up IEx with pre-bound variables etc…). Kudos to <a href="https://groups.google.com/forum/?utm_medium=email&amp;utm_source=footer#!topic/elixir-lang-talk/2wQOc5S0z1o" target="_blank" rel="external">Gary Rennie</a> for helping me find this when I was first looking for it.</p><h1 id="Building-an-API-with-Streams"><a href="#Building-an-API-with-Streams" class="headerlink" title="Building an API with Streams"></a>Building an API with Streams</h1><p>Back to our “intention” here. With all this background you should now be better equipped to digest most of the code in Drew’s original post. However, the <code>Github.ResultStream</code> module below is worth breaking down as it features a couple of things we haven’t yet discussed:</p><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># lib/github_resultstream.ex</span></span><br><span class="line"><span class="class"><span class="keyword">defmodule</span> <span class="title">Github</span></span>.<span class="constant">ResultStream </span><span class="keyword">do</span></span><br><span class="line">  <span class="keyword">alias</span> <span class="constant">Github.Gateway</span></span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">def</span> <span class="title">new</span></span>(url) <span class="keyword">do</span></span><br><span class="line">    <span class="constant">Stream.</span>resource(</span><br><span class="line">      <span class="keyword">fn</span> -&gt; fetch_page(url) <span class="keyword">end</span>,</span><br><span class="line">      &amp;process_page/<span class="number">1</span>,</span><br><span class="line">      <span class="keyword">fn</span> <span class="constant">_ </span>-&gt; <span class="keyword">nil</span> <span class="keyword">end</span></span><br><span class="line">    )</span><br><span class="line">  <span class="keyword">end</span></span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">defp</span> <span class="title">fetch_page</span></span>(url) <span class="keyword">do</span></span><br><span class="line">    response = <span class="constant">Gateway.</span>get!(url)</span><br><span class="line">    items = <span class="constant">Poison.</span>decode!(response.body)</span><br><span class="line">    <span class="comment"># <span class="doctag">TODO:</span> fix access to "Link" header</span></span><br><span class="line">    <span class="comment"># Works "by accident" in v1.1 of Elixir</span></span><br><span class="line">    <span class="comment"># Fixed (i.e. doesn't work) in v1.2:</span></span><br><span class="line">    links = parse_links(response.headers[<span class="string">"Link"</span>])</span><br><span class="line"></span><br><span class="line">    &#123;items, links[<span class="string">"next"</span>]&#125;</span><br><span class="line">  <span class="keyword">end</span></span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">def</span> <span class="title">parse_links</span></span>(<span class="keyword">nil</span>) <span class="keyword">do</span></span><br><span class="line">    %&#123;&#125;</span><br><span class="line">  <span class="keyword">end</span></span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">def</span> <span class="title">parse_links</span></span>(links_string) <span class="keyword">do</span></span><br><span class="line">    links = <span class="constant">String.</span>split(links_string, <span class="string">", "</span>)</span><br><span class="line"></span><br><span class="line">    <span class="constant">Enum.</span>map(links, <span class="keyword">fn</span> link -&gt;</span><br><span class="line">      [<span class="constant">_,</span>name] = <span class="constant">Regex.</span>run(~r&#123;rel=<span class="string">"([a-z]+)"</span>&#125;, link)</span><br><span class="line">      [<span class="constant">_,</span>url] = <span class="constant">Regex.</span>run(~r&#123;&lt;([^&gt;]+)&gt;&#125;, link)</span><br><span class="line">      short_url = <span class="constant">String.</span>replace(url, <span class="constant">Gateway.</span>endpoint, <span class="string">""</span>)</span><br><span class="line"></span><br><span class="line">      &#123;name, short_url&#125;</span><br><span class="line">    <span class="keyword">end</span>) |&gt; <span class="constant">Enum.</span>into(%&#123;&#125;)</span><br><span class="line">  <span class="keyword">end</span></span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">defp</span> <span class="title">process_page</span></span>(&#123;<span class="keyword">nil</span>, <span class="keyword">nil</span>&#125;) <span class="keyword">do</span></span><br><span class="line">    &#123;<span class="symbol">:halt</span>, <span class="keyword">nil</span>&#125;</span><br><span class="line">  <span class="keyword">end</span></span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">defp</span> <span class="title">process_page</span></span>(&#123;<span class="keyword">nil</span>, next_page_url&#125;) <span class="keyword">do</span></span><br><span class="line">    next_page_url</span><br><span class="line">    |&gt; fetch_page</span><br><span class="line">    |&gt; process_page</span><br><span class="line">  <span class="keyword">end</span></span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">defp</span> <span class="title">process_page</span></span>(&#123;items, next_page_url&#125;) <span class="keyword">do</span></span><br><span class="line">    &#123;items, &#123;<span class="keyword">nil</span>, next_page_url&#125;&#125;</span><br><span class="line">  <span class="keyword">end</span></span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><h2 id="Stream-resource-3"><a href="#Stream-resource-3" class="headerlink" title="Stream.resource/3"></a><a href="http://elixir-lang.org/docs/v1.2/elixir/Stream.html#resource/3" target="_blank" rel="external">Stream.resource/3</a></h2><p>To make sense of this, it’s probably best to just jump straight to the example given in the online docs:</p><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Stream.resource(start_fun, next_fun, after_fun)</span></span><br><span class="line"><span class="comment"># @spec resource((() -&gt; acc), (acc -&gt; &#123;element, acc&#125; | &#123;:halt, acc&#125;), (acc -&gt; term)) :: Enumerable.t</span></span><br><span class="line"><span class="constant">Stream.</span>resource(<span class="keyword">fn</span> -&gt; <span class="constant">File.</span>open!(<span class="string">"sample"</span>) <span class="keyword">end</span>,</span><br><span class="line">                <span class="keyword">fn</span> file -&gt;</span><br><span class="line">                  <span class="keyword">case</span> <span class="constant">IO.</span>read(file, <span class="symbol">:line</span>) <span class="keyword">do</span></span><br><span class="line">                    data <span class="keyword">when</span> is_binary(data) -&gt; &#123;[data], file&#125;</span><br><span class="line">                    <span class="constant">_ </span>-&gt; &#123;<span class="symbol">:halt</span>, file&#125;</span><br><span class="line">                  <span class="keyword">end</span></span><br><span class="line">                <span class="keyword">end</span>,</span><br><span class="line">                <span class="keyword">fn</span> file -&gt; <span class="constant">File.</span>close(file) <span class="keyword">end</span>)</span><br></pre></td></tr></table></figure><p>So <code>Stream.resource/3</code> takes 3 functions, <code>start_fun</code>, <code>next_fun</code>, and <code>after_fun</code>.</p><p>The result of <code>start_fun</code> is fed as an argument to <code>next_fun</code> which is responsible for generating the stream’s values. In this case, that result is a <a href="http://elixir-lang.org/getting-started/processes.html" target="_blank" rel="external">process</a> id (or PID):</p><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># we're using the file we wrote in iex(17) above</span></span><br><span class="line">iex(<span class="number">26</span>)&gt; <span class="constant">File.</span>open!(<span class="string">"./elixir_repo.json"</span>)</span><br><span class="line"><span class="comment">#PID&lt;0.64.0&gt;</span></span><br></pre></td></tr></table></figure><blockquote>Every time a file is opened, Elixir spawns a new process.<footer><cite><a href="http://elixir-lang.org/docs/v1.2/elixir/File.html" target="_blank" rel="external">File module doc</a></cite></footer></blockquote><p>Note that the result of <a href="http://elixir-lang.org/docs/v1.2/elixir/File.html#open!/2" target="_blank" rel="external">File.open!/2</a> is different from that of <a href="http://elixir-lang.org/docs/v1.2/elixir/File.html#open/2" target="_blank" rel="external">File.open/2</a> (also note that the second arg is optional in both cases):</p><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">iex(<span class="number">27</span>)&gt; <span class="constant">File.</span>open(<span class="string">"./elixir_repo.json"</span>)</span><br><span class="line">&#123;<span class="symbol">:ok</span>, <span class="comment">#PID&lt;0.66.0&gt;&#125;</span></span><br></pre></td></tr></table></figure><p>i.e. it’s wrapped in a tuple. You can read up on this in the “Trailing bang” section in the <a href="http://elixir-lang.org/docs/master/elixir/naming-conventions.html" target="_blank" rel="external">naming conventions</a> doc. The <a href="http://elixir-lang.org/docs/v1.2/elixir/File.html" target="_blank" rel="external">File module</a>‘s doc also mentions this in the “API” section.</p><p>This PID is called an <code>io_device</code> in the doc for the File module, and an <code>io_device</code> can be used as an argument to the <a href="http://elixir-lang.org/docs/v1.2/elixir/IO.html" target="_blank" rel="external">IO module</a> functions.</p><p>That is exactly what’s happening in <code>next_fun</code> above, which is passing <code>file</code> (bound to a PID), to <a href="http://elixir-lang.org/docs/v1.2/elixir/IO.html#read/2" target="_blank" rel="external">IO.read/2</a> to read a line from the <code>io_device</code>:</p><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">iex(<span class="number">28</span>)&gt; file = v(<span class="number">26</span>)</span><br><span class="line"><span class="comment">#PID&lt;0.64.0&gt;</span></span><br><span class="line">iex(<span class="number">29</span>)&gt; <span class="constant">IO.</span>read(file, <span class="symbol">:line</span>)</span><br><span class="line"><span class="string">"&#123;\n"</span></span><br><span class="line">iex(<span class="number">30</span>)&gt; <span class="constant">IO.</span>read(file, <span class="symbol">:line</span>)</span><br><span class="line"><span class="string">"  \"teams_url\": \"https://api.github.com/repos/elixir-lang/elixir/teams\",\n"</span></span><br><span class="line">iex(<span class="number">31</span>)&gt; <span class="constant">IO.</span>read(file, <span class="symbol">:line</span>)</span><br><span class="line"><span class="string">"  \"branches_url\": \"https://api.github.com/repos/elixir-lang/elixir/branches&#123;/branch&#125;\",\n"</span></span><br><span class="line">iex(<span class="number">32</span>)&gt; is_binary <span class="constant">IO.</span>read(file, <span class="symbol">:line</span>)</span><br><span class="line"><span class="keyword">true</span></span><br></pre></td></tr></table></figure><p>With the <code>:line</code> option, <code>IO.read/2</code> will keep giving us binary data until we read the whole file, at which point it will return an <code>:eof</code> atom which will match our second clause in our <code>next_fun</code>‘s <code>case</code> expression. So from this we can see that <code>next_fun</code> either returns <code>{[data], file}</code> or <code>{:halt, file}</code> - i.e. either the next line in the file as a string wrapped in a list or <code>:halt</code> to mark the end of the stream, in both cases accompanied by <code>file</code> our accumulator (the thing by which we’re able to keep streaming values).</p><blockquote>Successive values are generated by calling <code>next_fun</code> with the previous accumulator (the initial value being the result returned by <code>start_fun</code>) and it must return a tuple containing a <strong>list of items</strong> to be emitted and the next accumulator.<br><br><footer>Why do we wrap the read line in a list?<cite><a href="http://elixir-lang.org/docs/v1.2/elixir/Stream.html#resource/3" target="_blank" rel="external">Stream.resource/3 doc</a></cite></footer></blockquote><p>Finally, the <code>after_fun</code> is called with the accumulator (<code>file</code>) in order to give us an opportunity to clean up after ourselves, in this case, closing the file.</p><p>With that, we now know the control flow abstracted by <code>Stream.resource/3</code>. If we take another look at it’s usage in <code>Github.ResultStream</code>:</p><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">new</span></span>(url) <span class="keyword">do</span></span><br><span class="line">  <span class="constant">Stream.</span>resource(</span><br><span class="line">    <span class="keyword">fn</span> -&gt; fetch_page(url) <span class="keyword">end</span>,</span><br><span class="line">    &amp;process_page/<span class="number">1</span>,</span><br><span class="line">    <span class="keyword">fn</span> <span class="constant">_ </span>-&gt; <span class="keyword">nil</span> <span class="keyword">end</span></span><br><span class="line">  )</span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p>the other things to note before diving into the meat of its implementation (<code>process_page/1</code>), are the use of <a href="http://elixir-lang.org/crash-course.html#partials-in-elixir" target="_blank" rel="external">Elixir partials</a> to refer to <code>process_page/1</code> to act as <code>Stream.resource/3</code>‘s <code>next_fun</code>, and the definition of a “do nothing” function for the <code>after_fun</code> (since we have nothing to clean up). Originally, the “do nothing” function was defined as: <code>fn _ -&gt; end</code> in Drew’s post but the compiler gives a warning for this syntax as of Elixir 1.2, so we need to evaluate to <code>nil</code> (which is what used to happen anyway when no expression was given). Kudos to <a href="https://groups.google.com/forum/?utm_medium=email&amp;utm_source=footer#!msg/elixir-lang-talk/CQcWAkbmg9o/jkDq2_h8DAAJ" target="_blank" rel="external">René Föhring</a> for pointing this out.</p><blockquote>[Kernel] Warn when right hand side of -&gt; does not provide any expression<footer><cite><a href="https://github.com/elixir-lang/elixir/releases/tag/v1.2.0" target="_blank" rel="external">v1.2.0 release notes</a></cite></footer></blockquote><h2 id="The-rest-of-Github-ResultStream"><a href="#The-rest-of-Github-ResultStream" class="headerlink" title="The rest of Github.ResultStream"></a>The rest of Github.ResultStream</h2><p>We’re good to move on… so let’s tackle the “TODO” comment in the snippet below:</p><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">defp</span> <span class="title">fetch_page</span></span>(url) <span class="keyword">do</span></span><br><span class="line">  response = <span class="constant">Gateway.</span>get!(url)</span><br><span class="line">  items = <span class="constant">Poison.</span>decode!(response.body)</span><br><span class="line">  <span class="comment"># <span class="doctag">TODO:</span> fix access to "Link" header</span></span><br><span class="line">  <span class="comment"># Works "by accident" in v1.1 of Elixir</span></span><br><span class="line">  <span class="comment"># Fixed (i.e. doesn't work) in v1.2:</span></span><br><span class="line">  links = parse_links(response.headers[<span class="string">"Link"</span>])</span><br><span class="line"></span><br><span class="line">  &#123;items, links[<span class="string">"next"</span>]&#125;</span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p>Back when I was going through Drew’s post I was using Elixir v1.1.1 (there was no v1.2 yet). Lets try the following with v1.1.1:</p><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">iex(<span class="number">1</span>)&gt; headers = [&#123;<span class="string">"Server"</span>, <span class="string">"GitHub.com"</span>&#125;]</span><br><span class="line">[&#123;<span class="string">"Server"</span>, <span class="string">"GitHub.com"</span>&#125;]</span><br><span class="line">iex(<span class="number">2</span>)&gt; headers[<span class="string">"Server"</span>]</span><br><span class="line"><span class="string">"GitHub.com"</span></span><br></pre></td></tr></table></figure><p>When I started writing this post (a couple of days before the beginning of the year), v1.2 came out so I switched to the new hotness. Running the same thing in v1.2 gives:</p><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">iex(<span class="number">1</span>)&gt; headers = [&#123;<span class="string">"Server"</span>, <span class="string">"GitHub.com"</span>&#125;]</span><br><span class="line">[&#123;<span class="string">"Server"</span>, <span class="string">"GitHub.com"</span>&#125;]</span><br><span class="line">iex(<span class="number">2</span>)&gt; headers[<span class="string">"Server"</span>]</span><br><span class="line">** (<span class="constant">ArgumentError)</span> the <span class="constant">Access </span>calls <span class="keyword">for</span> keywords expect the key to be an atom, <span class="symbol">got:</span> <span class="string">"Server"</span></span><br><span class="line">    (elixir) lib/access.<span class="symbol">ex:</span><span class="number">64</span><span class="symbol">:</span> <span class="constant">Access.</span>fetch/<span class="number">2</span></span><br><span class="line">    (elixir) lib/access.<span class="symbol">ex:</span><span class="number">77</span><span class="symbol">:</span> <span class="constant">Access.</span>get/<span class="number">3</span></span><br></pre></td></tr></table></figure><p>At first, I thought something was broken in v1.2 but as <a href="https://groups.google.com/forum/?utm_medium=email&amp;utm_source=footer#!msg/elixir-lang-talk/Ydx4E_bmAP8/bugKvIg5EwAJ" target="_blank" rel="external">José Valim</a> points out, it looks like the behaviour in v1.1.1 was accidental! You can’t use that syntax on <code>headers</code> in this case because <code>headers</code> isn’t a keyword list or map. It’s a list of 2-element tuples but the first element in the tuple is not an atom (which would make it a keyword list) so this syntax won’t work. I thought I’d leave this bit in as I guess it’s “good to know”.</p><p>So we’re going to have to extract the “Link” header in some other way, which is just as well as it gives us the opportunity to look at a nice little trick I picked up from the blog post <a href="http://blog.plataformatec.com.br/2014/09/writing-assertive-code-with-elixir/" target="_blank" rel="external">Writing assertive code with Elixir</a> by <a href="https://twitter.com/josevalim?ref_src=twsrc%5Egoogle%7Ctwcamp%5Eserp%7Ctwgr%5Eauthor" target="_blank" rel="external">José Valim</a>:</p><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">defp</span> <span class="title">fetch_page</span></span>(url) <span class="keyword">do</span></span><br><span class="line">  response = <span class="constant">Gateway.</span>get!(url)</span><br><span class="line">  items = <span class="constant">Poison.</span>decode!(response.body)</span><br><span class="line">  links_map = </span><br><span class="line">    response.headers</span><br><span class="line">    |&gt; <span class="constant">Enum.</span>find_value(<span class="keyword">fn</span>(&#123;k, v&#125;) -&gt; k == <span class="string">"Link"</span> &amp;&amp; v <span class="keyword">end</span>)</span><br><span class="line">    |&gt; parse_links</span><br><span class="line">  &#123;items, links_map[<span class="string">"next"</span>]&#125;</span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p>First off, note the behaviour of the following:</p><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">iex(<span class="number">1</span>)&gt; <span class="keyword">true</span> &amp;&amp; <span class="string">"hello"</span></span><br><span class="line"><span class="string">"hello"</span></span><br><span class="line">iex(<span class="number">2</span>)&gt; <span class="string">"hello"</span> &amp;&amp; <span class="keyword">true</span></span><br><span class="line"><span class="keyword">true</span></span><br><span class="line">iex(<span class="number">3</span>)&gt; <span class="keyword">false</span> &amp;&amp; <span class="string">"hello"</span></span><br><span class="line"><span class="keyword">false</span></span><br><span class="line">iex(<span class="number">4</span>)&gt; <span class="string">"hello"</span> &amp;&amp; <span class="keyword">false</span></span><br><span class="line"><span class="keyword">false</span></span><br><span class="line">iex(<span class="number">5</span>)&gt; <span class="string">"hello"</span> &amp;&amp; <span class="string">"world"</span></span><br><span class="line"><span class="string">"world"</span></span><br></pre></td></tr></table></figure><blockquote>Provides a short-circuit operator that evaluates and returns the second expression only if the first one evaluates to true (i.e., it is not nil nor false). Returns the first expression otherwise.<footer><cite><a href="http://elixir-lang.org/docs/v1.2/elixir/Kernel.html#&&/2" target="_blank" rel="external">Kernel.&amp;&amp;/2 macro doc</a></cite></footer></blockquote><p>This means that whenever <code>k == &quot;Link&quot;</code> evaluates to <code>false</code>, <code>k == &quot;Link&quot; &amp;&amp; v</code> will always evaluate to <code>false</code>. Should it ever evaluate to <code>true</code>, then <code>k == &quot;Link&quot; &amp;&amp; v</code> would evaluate to <code>v</code></p><p><a href="http://elixir-lang.org/docs/v1.2/elixir/Enum.html#find_value/3" target="_blank" rel="external">Enum.find_value/3</a> is similar to <a href="http://elixir-lang.org/docs/v1.2/elixir/Enum.html#find/3" target="_blank" rel="external">Enum.find/3</a>, which I assume you’re already familiar with. The only difference is that instead of returning the element in the enumerable (list) for which the function you pass in evaluates to “not <code>false</code> or <code>nil</code>“, <code>Enum.find_value/3</code> returns the function’s “truthy” value instead (where “truthy” is “not <code>false</code> or <code>nil</code>“).</p><p>(One gotcha that comes to mind would be if, for e.g., the list we’re querying has something like {“Link”, nil}. Since <code>nil</code> is also <code>Enum.find_value/3</code>‘s default return value if the function you pass in never evaluates to truthy, you wouldn’t be able to tell if the <code>nil</code> you get back from <code>find_value/3</code> was a match or not).</p><p>This works well for our use case. Another approach suggested by <a href="https://groups.google.com/forum/#!msg/elixir-lang-talk/Ydx4E_bmAP8/A-LixvVmEwAJ" target="_blank" rel="external">Michał Muskała</a> uses <a href="http://elixir-lang.org/docs/v1.2/elixir/List.html#keyfind/4" target="_blank" rel="external">List.keyfind/4</a> and works just as well:</p><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">defp</span> <span class="title">fetch_page</span></span>(url) <span class="keyword">do</span></span><br><span class="line">  response = <span class="constant">Gateway.</span>get!(url)</span><br><span class="line">  items = <span class="constant">Poison.</span>decode!(response.body)</span><br><span class="line">  links_map = </span><br><span class="line">    response.headers</span><br><span class="line">    |&gt; <span class="constant">List.</span>keyfind(<span class="string">"Link"</span>, <span class="number">0</span>, &#123;<span class="keyword">nil</span>, <span class="keyword">nil</span>&#125;)</span><br><span class="line">    |&gt; elem(<span class="number">1</span>)</span><br><span class="line">    |&gt; parse_links</span><br><span class="line">  &#123;items, links_map[<span class="string">"next"</span>]&#125;</span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p>I wanted to mention it anyway because it’s “good to know” the functions in the standard lib. For e.g. before finding out about <code>List.keyfind/4</code>, I would use <code>Enum.find/3</code> but the former has a simpler API if you’re working with a list of tuples.</p><p>However, note that to get the same behaviour, you need to default to something like <code>{nil, nil}</code> in our case because if <code>List.keyfind/4</code> doesn’t find the key and returns <code>nil</code> (by default), then <a href="http://elixir-lang.org/docs/master/elixir/Kernel.html#elem/2" target="_blank" rel="external">elem/2</a> will throw an exception. We need to use <code>elem/2</code> to get the value part of the “Link” header in this case as <code>List.keyfind/4</code> gives us back the whole tuple.</p><p>So I’ll stick to <code>Enum.find_value/3</code> for this case. You might want to read that Google Group thread for another interesting approach suggested by <a href="https://groups.google.com/forum/?utm_medium=email&amp;utm_source=footer#!msg/elixir-lang-talk/Ydx4E_bmAP8/OVgPBHx1EwAJ" target="_blank" rel="external">Ben Wilson</a> which caters for multiple similar “keys” (i.e. first element of tuple) in the list. In our case, we know we’ll only have at most one “Link” header (possibly none), so it’s best not to use that approach here as the code would be longer (in both converting to a map and accessing the “Link” key which might not be there, and whose value would then be a list if it were there).</p><p>Ok ok… back on track:</p><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#  defp fetch_page(url) do</span></span><br><span class="line"><span class="comment">#    response = Gateway.get!(url)</span></span><br><span class="line"><span class="comment">#    items = Poison.decode!(response.body)</span></span><br><span class="line"><span class="comment">#    links_map = </span></span><br><span class="line"><span class="comment">#      response.headers</span></span><br><span class="line"><span class="comment">#      |&gt; Enum.find_value(fn(&#123;k, v&#125;) -&gt; k == "Link" &amp;&amp; v end)</span></span><br><span class="line"><span class="comment">#      |&gt; parse_links</span></span><br><span class="line"><span class="comment">#    &#123;items, links_map["next"]&#125;</span></span><br><span class="line"><span class="comment">#  end</span></span><br><span class="line">iex(<span class="number">1</span>)&gt; <span class="constant">Github.ResultStream.</span>parse_links(<span class="string">"&lt;https://api.github.com/organizations/9950313/repos?page=2&gt;; rel=\"next\", &lt;https://api.github.com/organizations/9950313/repos?page=3&gt;; rel=\"last\""</span>)</span><br><span class="line">%&#123;<span class="string">"last"</span> =&gt; <span class="string">"/organizations/9950313/repos?page=3"</span>,</span><br><span class="line">  <span class="string">"next"</span> =&gt; <span class="string">"/organizations/9950313/repos?page=2"</span>&#125;</span><br><span class="line">iex(<span class="number">2</span>)&gt; v(<span class="number">1</span>)[<span class="string">"next"</span>]</span><br><span class="line"><span class="string">"/organizations/9950313/repos?page=2"</span></span><br><span class="line">iex(<span class="number">3</span>)&gt; <span class="constant">Github.ResultStream.</span>parse_links(<span class="keyword">nil</span>)</span><br><span class="line">%&#123;&#125;</span><br><span class="line">iex(<span class="number">4</span>)&gt; %&#123;&#125;[<span class="string">"next"</span>]</span><br><span class="line"><span class="keyword">nil</span></span><br></pre></td></tr></table></figure><p>With that, you should now know how our <code>Stream.resource/3</code>‘s <code>start_fun</code> works and what our first <code>acc</code> (for <code>next_fun</code>) will look like. Our first <code>acc</code> will be <code>{items, nil | BitString}</code> where <code>items</code> is the list of maps decoded by <code>Poison</code> (i.e. the repos data), and the second element in the tuple is either <code>nil</code> if there’s no more data to get through pagination, or the link to follow if there is.</p><p>Now, the only thing left is understanding our <code>next_fun</code>:</p><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">defp</span> <span class="title">process_page</span></span>(&#123;<span class="keyword">nil</span>, <span class="keyword">nil</span>&#125;) <span class="keyword">do</span></span><br><span class="line">  &#123;<span class="symbol">:halt</span>, <span class="keyword">nil</span>&#125;</span><br><span class="line"><span class="keyword">end</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">defp</span> <span class="title">process_page</span></span>(&#123;<span class="keyword">nil</span>, next_page_url&#125;) <span class="keyword">do</span></span><br><span class="line">  next_page_url</span><br><span class="line">  |&gt; fetch_page</span><br><span class="line">  |&gt; process_page</span><br><span class="line"><span class="keyword">end</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">defp</span> <span class="title">process_page</span></span>(&#123;items, next_page_url&#125;) <span class="keyword">do</span></span><br><span class="line">  &#123;items, &#123;<span class="keyword">nil</span>, next_page_url&#125;&#125;</span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p>First off, know that this is pattern matching at work again and that pattern matching happens top-to-bottom. So if we pass <code>process_page/1</code> no data and no next link - <code>{nil, nil}</code> - the first clause will match and it’ll give us back <code>{:halt, nil}</code> (this will always happen at some point because this thing’s recursive and that’s the base case).</p><p>Let’s take the case of <code>fetch_page(&quot;/orgs/elixir-lang/repos&quot;)</code>, which as we saw before, doesn’t have enough data to need pagination - hopefully that will change soon ;)</p><p>In <em>elixir-lang</em>‘s case, it’s <code>{items, nil}</code> where <code>items</code> isn’t <code>nil</code> (thankfully!). This means the 3rd clause will match and our first evaluation of <code>process_page/1</code> gives <code>{items, {nil, nil}}</code>.</p><p>Remember from our discussion of <a href="#Stream-resource/3">Stream.resource/3 above</a> that the first element in the tuple returned by <code>Stream.resource/3</code>‘s <code>next_fun</code>, if not <code>:halt</code>, is a list of data, the data which our stream produces. We’re basically passing that data to <code>Stream.resource/3</code> and using the second element in the tuple (the accumulator) to keep getting more data (until exhaustion), through <code>next_fun</code> - which is now invoked again with <code>{nil, nil}</code> and we already know what will happen next.</p><p>But what if we were querying something like “/orgs/nodejs/repos”? In that case, <code>next_page_url</code> would not be <code>nil</code> and our <code>acc</code> would be <code>{nil, url}</code>. The next time our stream is forced for more data, <code>next_fun</code> will be called with this <code>acc</code> which would match the 2nd clause. This will hit Github’s API for the next paginated data, and return <code>{:halt, nil}</code> if no data comes back, or <code>{items, {nil, nil | next_page_url}}</code> if there is data (note that it would be problematic if Github’s API would, for some weird reason (a.k.a bug), return no data but also include a “Link” header with a next URL to follow in its reply as we would basically end up in an infinite loop).</p><p>In the spirit of being explicit about anything that might be ambiguous (a.k.a might as well go all the way), if Github comes back with data <em>and</em> a “Link” header with a next URL to follow, then when our stream is forced for more data, <code>process_page/1</code> will be called with <code>{nil, next_page_url}</code></p><p>If Github returns no “Link” header with a next URL to follow, then when our stream is next forced for more data, <code>process_page/1</code> will be called with <code>{nil, nil}</code>, but <em>in both cases</em> the data Github returned is fed back to <code>Stream.resource/3</code> via <code>items</code>.</p><h1 id="Test-drive"><a href="#Test-drive" class="headerlink" title="Test drive"></a>Test drive</h1><p>The <code>Github</code> module below exposes a clean API to our users:</p><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># lib/github.ex</span></span><br><span class="line"><span class="class"><span class="keyword">defmodule</span> <span class="title">Github</span></span> <span class="keyword">do</span></span><br><span class="line">  <span class="keyword">alias</span> <span class="constant">Github.ResultStream</span></span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">def</span> <span class="title">repos</span></span>(organization) <span class="keyword">do</span></span><br><span class="line">    <span class="constant">ResultStream.</span>new(<span class="string">"/orgs/<span class="subst">#&#123;organization&#125;</span>/repos"</span>)</span><br><span class="line">  <span class="keyword">end</span></span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p>Below taking this thing for a spin, go ahead and add <code>IO.puts(&quot;Url: #{url}&quot;)</code> to <code>Github.Gateway.process_url/1</code> so we can confirm how many requests are being made (as we’ve seen before, HTTPoison uses this function internally):</p><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">iex(<span class="number">1</span>)&gt; repo_stream = <span class="string">"nodejs"</span> |&gt; <span class="constant">Github.</span>repos |&gt;</span><br><span class="line">...(<span class="number">1</span>)&gt;   <span class="constant">Stream.</span>map(<span class="keyword">fn</span> repo_map -&gt; &#123;repo_map[<span class="string">"full_name"</span>], repo_map[<span class="string">"forks"</span>]&#125; <span class="keyword">end</span>)</span><br><span class="line"><span class="comment">#Stream&lt;[enum: #Function&lt;46.94256892/2 in Stream.resource/3&gt;,</span></span><br><span class="line"> <span class="symbol">funs:</span> [<span class="comment">#Function&lt;29.94256892/1 in Stream.map/2&gt;]]&gt;</span></span><br><span class="line">iex(<span class="number">2</span>)&gt; repo_stream |&gt; <span class="constant">Enum.</span>take(<span class="number">4</span>)</span><br><span class="line"><span class="constant">Url:</span> /orgs/nodejs/repos</span><br><span class="line">[&#123;<span class="string">"nodejs/http-parser"</span>, <span class="number">641</span>&#125;, &#123;<span class="string">"nodejs/node-v0.x-archive"</span>, <span class="number">8508</span>&#125;,</span><br><span class="line"> &#123;<span class="string">"nodejs/node-gyp"</span>, <span class="number">354</span>&#125;, &#123;<span class="string">"nodejs/readable-stream"</span>, <span class="number">67</span>&#125;]</span><br><span class="line">iex(<span class="number">3</span>)&gt; repo_stream |&gt; <span class="constant">Enum.</span>take(<span class="number">40</span>)</span><br><span class="line"><span class="constant">Url:</span> /orgs/nodejs/repos</span><br><span class="line"><span class="constant">Url:</span> /organizations/<span class="number">9950313</span>/repos?page=<span class="number">2</span></span><br><span class="line">[&#123;<span class="string">"nodejs/http-parser"</span>, <span class="number">641</span>&#125;, &#123;<span class="string">"nodejs/node-v0.x-archive"</span>, <span class="number">8508</span>&#125;,</span><br><span class="line"> &#123;<span class="string">"nodejs/node-gyp"</span>, <span class="number">354</span>&#125;, &#123;<span class="string">"nodejs/readable-stream"</span>, <span class="number">67</span>&#125;,</span><br><span class="line"> &#123;<span class="string">"nodejs/node-addon-examples"</span>, <span class="number">140</span>&#125;, &#123;<span class="string">"nodejs/nan"</span>, <span class="number">180</span>&#125;,</span><br><span class="line"> &#123;<span class="string">"nodejs/nodejs.org-archive"</span>, <span class="number">83</span>&#125;, &#123;<span class="string">"nodejs/build"</span>, <span class="number">26</span>&#125;,</span><br><span class="line"> &#123;<span class="string">"nodejs/roadmap"</span>, <span class="number">34</span>&#125;, &#123;<span class="string">"nodejs/build-containers"</span>, <span class="number">5</span>&#125;, &#123;<span class="string">"nodejs/node"</span>, <span class="number">2382</span>&#125;,</span><br><span class="line"> &#123;<span class="string">"nodejs/iojs.org"</span>, <span class="number">138</span>&#125;, &#123;<span class="string">"nodejs/logos"</span>, <span class="number">40</span>&#125;, &#123;<span class="string">"nodejs/docker-node"</span>, <span class="number">72</span>&#125;,</span><br><span class="line"> &#123;<span class="string">"nodejs/build-container-sync"</span>, <span class="number">2</span>&#125;, &#123;<span class="string">"nodejs/doc-tool"</span>, <span class="number">7</span>&#125;,</span><br><span class="line"> &#123;<span class="string">"nodejs/docker-iojs"</span>, <span class="number">28</span>&#125;, &#123;<span class="string">"nodejs/tracing-wg"</span>, <span class="number">8</span>&#125;, &#123;<span class="string">"nodejs/nodejs-es"</span>, <span class="number">3</span>&#125;,</span><br><span class="line"> &#123;<span class="string">"nodejs/nodejs-ko"</span>, <span class="number">31</span>&#125;, &#123;<span class="string">"nodejs/nodejs-nl"</span>, <span class="number">2</span>&#125;, &#123;<span class="string">"nodejs/nodejs-de"</span>, <span class="number">4</span>&#125;,</span><br><span class="line"> &#123;<span class="string">"nodejs/nodejs-pt"</span>, <span class="number">6</span>&#125;, &#123;<span class="string">"nodejs/nodejs-ru"</span>, <span class="number">14</span>&#125;, &#123;<span class="string">"nodejs/nodejs-fr"</span>, <span class="number">6</span>&#125;,</span><br><span class="line"> &#123;<span class="string">"nodejs/nodejs-da"</span>, <span class="number">1</span>&#125;, &#123;<span class="string">"nodejs/nodejs-hi"</span>, <span class="number">2</span>&#125;, &#123;<span class="string">"nodejs/nodejs-ja"</span>, <span class="number">9</span>&#125;,</span><br><span class="line"> &#123;<span class="string">"nodejs/nodejs-no"</span>, <span class="number">5</span>&#125;, &#123;<span class="string">"nodejs/nodejs-hu"</span>, <span class="number">4</span>&#125;, &#123;<span class="string">"nodejs/nodejs-he"</span>, <span class="number">1</span>&#125;,</span><br><span class="line"> &#123;<span class="string">"nodejs/nodejs-it"</span>, <span class="number">1</span>&#125;, &#123;<span class="string">"nodejs/nodejs-sv"</span>, <span class="number">0</span>&#125;, &#123;<span class="string">"nodejs/nodejs-tr"</span>, <span class="number">4</span>&#125;,</span><br><span class="line"> &#123;<span class="string">"nodejs/nodejs-ka"</span>, <span class="number">0</span>&#125;, &#123;<span class="string">"nodejs/nodejs-mk"</span>, <span class="number">0</span>&#125;, &#123;<span class="string">"nodejs/nodejs-pl"</span>, <span class="number">0</span>&#125;,</span><br><span class="line"> &#123;<span class="string">"nodejs/nodejs-el"</span>, <span class="number">1</span>&#125;, &#123;<span class="string">"nodejs/nodejs-id"</span>, <span class="number">6</span>&#125;, &#123;<span class="string">"nodejs/nodejs-cs"</span>, <span class="number">0</span>&#125;]</span><br></pre></td></tr></table></figure><p>As we saw with <code>curl</code> + <code>jq</code> in the <a href="#How_to_fetch_Github_organization_repos_and_their_pagination">How to fetch Github organization repos and their pagination</a>, Github will only ever give us a max of 30 repos per request, so when we <code>Enum.take(40)</code> in <code>iex(2)</code> above, we get the second request’s URL printed out as our stream needs to paginate. In comparison, only one request ever happens in <code>iex(1)</code> which only ever takes 4 repos from the stream.</p><h1 id="How-to-install-Elixir-with-asdf"><a href="#How-to-install-Elixir-with-asdf" class="headerlink" title="How to install Elixir with asdf"></a>How to install Elixir with asdf</h1><p><a href="https://github.com/HashNuke/asdf" target="_blank" rel="external">asfd</a> is an extendable version manager for a couple of platforms (currently, <a href="https://github.com/HashNuke/asdf-ruby" target="_blank" rel="external">Ruby</a>, <a href="https://github.com/HashNuke/asdf-nodejs" target="_blank" rel="external">Node.js</a>, <a href="https://github.com/HashNuke/asdf-elixir" target="_blank" rel="external">Elixir</a>, <a href="https://github.com/HashNuke/asdf-erlang" target="_blank" rel="external">Erlang</a>, and <a href="https://github.com/Stratus3D/asdf-lua" target="_blank" rel="external">Lua</a>) i.e. you can use it to install, uninstall, and change between different versions of the supported platforms.</p><p>To install it on your system, simply <code>git clone https://github.com/HashNuke/asdf.git ~/.asdf</code> and source it from a startup script like <code>.bashrc</code> or <code>.bash_profile</code> or similar, by running:</p><p><code>echo &#39;. $HOME/.asdf/asdf.sh&#39; &gt;&gt; ~/.bash_profile</code></p><p>i.e. append <code>. $HOME/.asdf/asdf.sh</code> to <code>~/.bash_profile</code>.</p><p>To get started using Elixir, you then need to install both Erlang and Elixir on your system using the respective asdf plugin for each:</p><figure class="highlight crystal"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$ </span>asdf plugin-add erlang <span class="symbol">https:</span>/<span class="regexp">/github.com/</span><span class="constant">HashNuke</span>/asdf-erlang.git</span><br><span class="line"><span class="comment"># ...</span></span><br><span class="line"><span class="variable">$ </span>asdf list-all erlang</span><br><span class="line"><span class="number">18.1</span></span><br><span class="line"><span class="comment"># ...</span></span><br><span class="line"><span class="variable">$ </span>asdf install erlang <span class="number">18.1</span></span><br><span class="line"><span class="comment"># ...</span></span><br><span class="line"><span class="variable">$ </span>asdf plugin-add elixir <span class="symbol">https:</span>/<span class="regexp">/github.com/</span><span class="constant">HashNuke</span>/asdf-elixir.git</span><br><span class="line"><span class="comment"># ...</span></span><br><span class="line"><span class="variable">$ </span>asdf list-all elixir</span><br><span class="line"><span class="comment"># 1.1.1</span></span><br><span class="line"><span class="comment"># .... <span class="doctag">Note:</span> don't worry if 1.2.0 is not listed, install it anyway (the list is hard-coded)</span></span><br><span class="line"><span class="variable">$ </span>asdf install elixir <span class="number">1.2</span>.<span class="number">0</span></span><br><span class="line"><span class="comment"># ...</span></span><br></pre></td></tr></table></figure><p>One last thing I’d like to point out about asdf is its <a href="https://github.com/HashNuke/asdf#the-tool-versions-file" target="_blank" rel="external">.tool-versions</a> feature which you can use to set default versions of the tools you use, both globally (by using it in your home directory), as well as on a per-project basis.</p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h1 id=&quot;Intro&quot;&gt;&lt;a href=&quot;#Intro&quot; class=&quot;headerlink&quot; title=&quot;Intro&quot;&gt;&lt;/a&gt;Intro&lt;/h1&gt;&lt;p&gt;This post is based on &lt;a href=&quot;http://drewolson.org/&quot; targ
      
    
    </summary>
    
      <category term="programming" scheme="http://justincalleja.com/categories/programming/"/>
    
    
      <category term="elixir" scheme="http://justincalleja.com/tags/elixir/"/>
    
  </entry>
  
  <entry>
    <title>Creating a Ruby on Rails Vagrant box</title>
    <link href="http://justincalleja.com/2015/12/26/ruby-on-rails-vagrant-box/"/>
    <id>http://justincalleja.com/2015/12/26/ruby-on-rails-vagrant-box/</id>
    <published>2015-12-26T00:00:00.000Z</published>
    <updated>2020-04-07T09:25:01.194Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Intro"><a href="#Intro" class="headerlink" title="Intro"></a>Intro</h1><p>In this post we’ll see how to create a virtual machine running <a href="http://www.ubuntu.com/" target="_blank" rel="external">Ubuntu</a> which has everything installed to start developing <a href="http://rubyonrails.org/" target="_blank" rel="external">Rails</a> applications.</p><h2 id="Prerequisites"><a href="#Prerequisites" class="headerlink" title="Prerequisites"></a>Prerequisites</h2><p>You’ll need to have <a href="https://www.virtualbox.org/wiki/Downloads" target="_blank" rel="external">VirtualBox</a> and <a href="https://www.vagrantup.com/downloads.html" target="_blank" rel="external">Vagrant</a> installed before starting (if you intend to follow along). I’m using VirtualBox version 5.0.10 r104061 and Vagrant version 1.7.4.</p><h1 id="Starting-up-a-VM-with-Vagrant"><a href="#Starting-up-a-VM-with-Vagrant" class="headerlink" title="Starting up a VM with Vagrant"></a>Starting up a VM with Vagrant</h1><p>Start off by creating an empty directory, e.g. <code>rails-box</code>, and <code>cd</code> into it. This is where we’ll be building our template box containing everything we need to start writing a new Rails application. After building it, we’ll be able to install the template on our system and use it whenever we want an Ubuntu VM pre-installed with the software we need to start writing Rails apps.</p><p>In order to kick off the process, go ahead and run <code>vagrant init ubuntu/trusty64</code> which will give us a <code>Vagrantfile</code> specifying which box we want to use (in our case, it’s <code>ubuntu/trusty64</code>). A box whose name is in the format <strong>vendor/name</strong> means Vagrant will look for this box on <a href="https://atlas.hashicorp.com/boxes/search" target="_blank" rel="external">Hashicorp</a>‘s servers if it fails to find it on your host machine.</p><p>Note, if you don’t fancy all the comments in the generated Vagrantfile, feel free to delete the file and generate it again using the <strong>-m</strong> flag: <code>vagrant init -m ubuntu/trusty64</code>.</p><p>With our Vagrantfile in place, go ahead and start the VM with <code>vagrant up</code>. This can take quite some time if you don’t already have a template for <code>ubuntu/trusty64</code> on your machine. In this case, Vagrant will need to download the box from Hashicorp’s servers and store it in your <a href="https://docs.vagrantup.com/v2/other/environmental-variables.html" target="_blank" rel="external">$VAGRANT_HOME</a> which by default is <code>~/.vagrant.d</code>.</p><p>Downloading the box will be the longest part of <code>vagrant up</code>. After which, it also needs to extract and install the template box in VirtualBox. Apart from the stdout log output, you’ll be able to see when this is done in VirtualBox’s GUI Manager as another entry for the new box will be listed (with status “Running”).</p><h1 id="Installing-software"><a href="#Installing-software" class="headerlink" title="Installing software"></a>Installing software</h1><p>Now that Ubuntu’s running, go ahead and log into the box via ssh with: <code>vagrant ssh</code> (run this in the same directory containing your Vagrantfile). Once logged in, if you run <code>ruby -v</code> you’ll see that it’s a bit old (for me it’s <code>ruby 1.9.3p484</code>).</p><p>So the first thing we’ll do is upgrade our Ruby. There’s a couple of ways of doing this. In the past, I remember (successfully) using <a href="https://rvm.io/" target="_blank" rel="external">RVM</a> for this (and more). As I’m just returning to Ruby land after 2 years of meddling in other things, I’m following along <a href="https://www.manning.com/books/rails-4-in-action" target="_blank" rel="external">Rails 4 in Action</a>, so we’ll be using the approach suggested there.</p><p>To get started, we need a copy of <a href="https://github.com/postmodern/ruby-install" target="_blank" rel="external">ruby-install</a>, which you can get by running the following in your ssh session at the command prompt:</p><figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">~$ wget -O ruby-install-<span class="number">0.5</span>.<span class="number">0</span><span class="class">.tar</span><span class="class">.gz</span> https:<span class="comment">//github.com/postmodern/ruby-install/archive/v0.5.0.tar.gz</span></span><br></pre></td></tr></table></figure><p>I’m using the latest at the time of writing but feel free to get any updated version. You can then simply extract and install:</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">~$ tar -xzvf ruby-install-<span class="number">0.5</span><span class="number">.0</span>.tar.gz</span><br><span class="line">...</span><br><span class="line">~$ cd ruby-install-<span class="number">0.5</span><span class="number">.0</span>/</span><br><span class="line">~/ruby-install-<span class="number">0.5</span><span class="number">.0</span>$ sudo make install</span><br></pre></td></tr></table></figure><p>You should now have <code>ruby-install</code> on your PATH and be able to execute it at the command prompt. Go ahead and install the version of Ruby you want with: <code>ruby-install ruby 2.2.1</code> (and yes, this does take a while). When it’s done, you’ll get something like:</p><blockquote><p>>>> Successfully installed ruby 2.2.1 into /home/vagrant/.rubies/ruby-2.2.1</p></blockquote><p>Cool, but if you <code>ruby -v</code>, you’ll still see the old version. First off, since this is going to be a template box, it’s probably best to clean up after ourselves now that <code>ruby-install</code> is, well, installed:</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">~/ruby-install-<span class="number">0.5</span><span class="number">.0</span>$ cd ~</span><br><span class="line">~$ rm -rf ruby-install-<span class="number">0.5</span><span class="number">.0</span> src ruby-install-<span class="number">0.5</span><span class="number">.0</span>.tar.gz</span><br></pre></td></tr></table></figure><p>Now, moving on to setting which version of Ruby we want to use. For this we’ll use <a href="https://github.com/postmodern/chruby" target="_blank" rel="external">chruby</a>, and the process is quite similar:</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">~$ wget -O chruby-<span class="number">0.3</span><span class="number">.9</span>.tar.gz https:<span class="comment">//github.com/postmodern/chruby/archive/v0.3.9.tar.gz</span></span><br><span class="line">~$ tar -xzvf chruby-<span class="number">0.3</span><span class="number">.9</span>.tar.gz</span><br><span class="line">~$ cd chruby-<span class="number">0.3</span><span class="number">.9</span>/</span><br><span class="line">~/chruby-<span class="number">0.3</span><span class="number">.9</span>$ sudo make install</span><br><span class="line">~/chruby-<span class="number">0.3</span><span class="number">.9</span>$ cd ..</span><br><span class="line">~$ rm -rf ./chruby-<span class="number">0.3</span><span class="number">.9</span> chruby-<span class="number">0.3</span><span class="number">.9</span>.tar.gz</span><br></pre></td></tr></table></figure><p>After installing chruby in your system, you’ll need to source it from one of your startup scripts:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">~$ <span class="built_in">echo</span> <span class="operator">-e</span> <span class="string">"\nsource /usr/local/share/chruby/chruby.sh"</span> &gt;&gt; ~/.bashrc</span><br></pre></td></tr></table></figure><p>You can also source the <code>auto.sh</code> script if you want to enable the automatic switching of Ruby versions based off of the presence/contents of a <code>.ruby-version</code> file:</p><figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">~<span class="variable">$ </span>echo <span class="string">"source /usr/local/share/chruby/auto.sh"</span> <span class="prompt">&gt;&gt; </span>~<span class="regexp">/.bashrc</span></span><br></pre></td></tr></table></figure><p>This isn’t strictly necessary, but why not. It comes in handy if you’re working on a project which requires the use of a particular version of Ruby. You could save a <code>.ruby-version</code> file with that particular version as content (in your project’s root). Now, every time you <code>cd</code> into that project, you don’t have to remember to switch to that particular version of Ruby as it’s done automatically for you.</p><p>Moving on, you can <code>exit</code> your ssh session and log in again with <code>vagrant ssh</code> to actually source these files. You now have <code>chruby</code> on your PATH and running it will list out the Ruby versions you have installed. To finally actually use the version we previously installed, run: <code>chruby ruby-2.2.1</code>.</p><p>Now you can verify we’re using that version of Ruby with <code>ruby -v</code>. Since you don’t want to manually have to stay doing this every time you log in, add this to your <code>.bashrc</code> file or make use of the <code>auto.sh</code> feature we enabled:</p><figure class="highlight vim"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">~$ <span class="keyword">echo</span> <span class="string">"chruby ruby-2.2.1"</span> &gt;&gt; ~/.bashrc</span><br><span class="line">~$ # <span class="built_in">and</span>/<span class="built_in">or</span></span><br><span class="line">~$ sudo <span class="keyword">sh</span> -<span class="keyword">c</span> <span class="string">'echo "ruby-2.2.1" &gt;&gt; /.ruby-version'</span></span><br></pre></td></tr></table></figure><p>It’s easiest for us to stick with the <code>.bashrc</code> approach but if you opt to use <code>.ruby-version</code>, put it in the root directory as shown above. We’ll later be using Rails in <code>/vagrant</code> which is outside <code>/home/vagrant</code> so a <code>.ruby-version</code> there wouldn’t be picked up by <code>chruby</code>.</p><p>Now it’s Rails’s turn:</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">~$ gem install rails -v <span class="number">4.2</span><span class="number">.1</span></span><br></pre></td></tr></table></figure><p>Confirm everything’s in order with <code>rails -v</code>.</p><p>Again, following along the Rails 4 in Action book, install the following header files via apt-get:</p><figure class="highlight q"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">~$ sudo apt-<span class="built_in">get</span> <span class="keyword">update</span> -y &amp;&amp; sudo apt-<span class="built_in">get</span> install -y libsqlite3-<span class="built_in">dev</span> libpq-<span class="built_in">dev</span> libmysqlclient-<span class="built_in">dev</span></span><br></pre></td></tr></table></figure><h2 id="Installing-a-Javascript-runtime"><a href="#Installing-a-Javascript-runtime" class="headerlink" title="Installing a Javascript runtime"></a>Installing a Javascript runtime</h2><p>The last piece of software we’ll need to install is a Javascript runtime. I’ll be going with <a href="https://nodejs.org/en/" target="_blank" rel="external">Node.js</a> as that’s what I’m more familiar with. However, if I <code>apt-cache policy nodejs</code> to see which version of Node I’d get if I were to <code>apt-get install</code> it, I get back <code>0.10.25</code>… not exactly the latest and greatest.</p><p>As we’ve done with Ruby, we’ll use tools which will take care of installing and managing our versions of Node. I’m personally somewhat familiar with 2 of these: <a href="https://github.com/creationix/nvm" target="_blank" rel="external">nvm</a> and <a href="https://github.com/HashNuke/asdf" target="_blank" rel="external">asdf</a>, and I’d like to quickly cover basic usage of both here. However, nvm is the more mature of the two from its Github stats (and through personal usage). It is also more specialized in that it’s only concerned with catering for Node.js.</p><p>asdf’s appeal is in its pluggability, as playfully put in the <a href="https://github.com/HashNuke/asdf/blob/master/ballad-of-asdf.md" target="_blank" rel="external">ballad-of-asdf.md</a>.</p><h3 id="nvm"><a href="#nvm" class="headerlink" title="nvm"></a>nvm</h3><p>To install nvm run the following (you will find the URL to the latest version of nvm in its Github <a href="https://github.com/creationix/nvm" target="_blank" rel="external">README.md</a>):</p><figure class="highlight crystal"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">~<span class="variable">$ </span>curl -o- <span class="symbol">https:</span>/<span class="regexp">/raw.githubusercontent.com/creationix</span><span class="regexp">/nvm/v</span>0.<span class="number">29.0</span>/install.sh | bash</span><br></pre></td></tr></table></figure><p>Log out and back into a new ssh session and you should be good with <code>nvm</code> on your PATH. To install Node via nvm, you’d run something like:</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">~$ nvm install <span class="number">5.3</span><span class="number">.0</span></span><br></pre></td></tr></table></figure><p>You can find the latest version number for Node from <a href="https://nodejs.org/dist/" target="_blank" rel="external">here</a>. You should be able to <code>node -v</code> and get the version now, but if at this point you were to log out and back in to the machine, your session wouldn’t have Node on the PATH. In order to fix this, create a <code>.nvmrc</code> file like so:</p><figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">~<span class="variable">$ </span>echo <span class="string">"5.3.0"</span> <span class="prompt">&gt;&gt; </span>~<span class="regexp">/.nvmrc</span></span><br></pre></td></tr></table></figure><h3 id="asdf"><a href="#asdf" class="headerlink" title="asdf"></a>asdf</h3><p>If you’ve followed the nvm instructions, you’re good to go. You could install asdf anyway, and even install versions of Node with it - i.e. you can have both nvm and asdf on your system and then choose which one you want to use by sourcing the tool of choice from your <code>.bashrc</code>. Uninstalling either of them is simply a matter of not sourcing in <code>.bashrc</code> and deleting their home directory (<code>~/.nvm</code> or <code>~/.asdf</code>).</p><p>To get started, install git, clone asdf, and source its script file from your init script:</p><figure class="highlight stata"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">~$ sudo apt-get install git -<span class="literal">y</span></span><br><span class="line">~$ git clone https:<span class="comment">//github.com/HashNuke/asdf.git ~/.asdf</span></span><br><span class="line">~$ echo -<span class="keyword">e</span> '\<span class="keyword">n</span>. <span class="label">$HOME</span>/.asdf/asdf.<span class="keyword">sh</span>' &gt;&gt; ~/.bashrc</span><br></pre></td></tr></table></figure><p>Log out and back in. You’ll then need to install the Node.js plugin with:</p><figure class="highlight vim"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">~$ asdf plugin-<span class="built_in">add</span> nodejs http<span class="variable">s:</span>//github.<span class="keyword">com</span>/HashNuke/asdf-nodejs.git</span><br></pre></td></tr></table></figure><p>and then Node itself with:</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">~$ asdf install nodejs <span class="number">5.3</span><span class="number">.0</span></span><br></pre></td></tr></table></figure><p>The same file based setting of version number can be achieved with:</p><figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">~<span class="variable">$ </span>echo <span class="string">"nodejs 5.3.0"</span> <span class="prompt">&gt;&gt; </span>~<span class="regexp">/.tool-versions</span></span><br></pre></td></tr></table></figure><h1 id="Packaging-up-our-box"><a href="#Packaging-up-our-box" class="headerlink" title="Packaging up our box"></a>Packaging up our box</h1><p>At this point, our box seems to be well equipped for Rails development so we’ll create a template out of it.</p><p>In your host OS (in <code>Vagrantfile</code> dir), stop the running VM and package it up with:</p><figure class="highlight crystal"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$ </span>vagrant halt</span><br><span class="line"><span class="variable">$ </span>vagrant package --output rails.box</span><br></pre></td></tr></table></figure><p>When it’s done, you’ll get <code>rails.box</code>, a template box from which you can later re-create the exact same VM with all the software we’ve installed in it.</p><p>This box isn’t yet installed in Vagrant - something you can verify with <code>vagrant box list</code>. You can install it with:</p><figure class="highlight processing"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ vagrant <span class="built_in">box</span> <span class="built_in">add</span> rails ./rails.<span class="built_in">box</span></span><br></pre></td></tr></table></figure><p>which will add the generated box under the name <code>rails</code>.</p><p>To use the installed box, go to an empty directory (where you intend to start developing your Rails app), and initialize + start it with:</p><figure class="highlight crystal"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">~<span class="regexp">/rails-projects$ vagrant init -m rails</span><br><span class="line">~/rails</span>-projects<span class="variable">$ </span>vagrant up</span><br></pre></td></tr></table></figure><p>If you now ssh into the new box with <code>vagrant ssh</code> you can verify that you have all the software we’ve previously installed.</p><h1 id="Accessing-Rails-from-the-host-OS"><a href="#Accessing-Rails-from-the-host-OS" class="headerlink" title="Accessing Rails from the host OS"></a>Accessing Rails from the host OS</h1><p>So far so good. We can now go on any machine, install Virtual Box, Vagrant, and the box we just created, and get a VM with all the software we need to start a Rails project.</p><p>That said, lets kick off a vanilla Rails app to demo the first issue you’ll have with this setup, namely, accessing your Rails app from a browser running on your host OS.</p><p>In your guest OS, go to the default shared directory on any stock Vagrant box, <code>/vagrant</code>. In it you will find the <code>Vagrantfile</code> we generated with <code>vagrant init -m rails</code> above:</p><figure class="highlight smalltalk"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">~<span class="char">$ </span>cd /vagrant/</span><br><span class="line">/vagrant<span class="char">$ </span>cat <span class="class">Vagrantfile</span></span><br><span class="line"><span class="class">Vagrant</span>.configure(<span class="number">2</span>) do <span class="localvars">|config|</span></span><br><span class="line">  config.vm.box = <span class="comment">"rails"</span></span><br><span class="line">end</span><br></pre></td></tr></table></figure><p>Working here allows us to use our guest OS to execute any Rails commands, and our host OS to author the app with the software we already have installed.</p><p>Go ahead and generate a new Rails app with:</p><figure class="highlight actionscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/vagrant$ rails <span class="keyword">new</span> tmpapp</span><br></pre></td></tr></table></figure><p>and then start it with:</p><figure class="highlight crystal"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">/vagrant<span class="variable">$ </span>cd tmpapp</span><br><span class="line">/vagrant/tmpapp<span class="variable">$ </span>rails server</span><br></pre></td></tr></table></figure><p>You will notice that Rails 4.2.1 starts up on <code>http://localhost:3000</code>. <code>localhost</code> is the guest OS’s loopback address, so there’s no way you’re going to access that endpoint from a browser on your host OS. Even if you were to start Rails listening on <code>0.0.0.0</code> for “listen on all IP addresses on this machine”, you still wouldn’t be able to access Rails from a browser on your host OS because the two aren’t on the same network. </p><p>To get around this, you <em>could</em> stay port forwarding the ports you’re interested in (say, 8080 on the host maps to 3000 on the guest), but that gets annoying really quickly if you later need to open other ports. I’ll opt for putting the two on the same private network.</p><p>The configuration required to tell Vagrant to set up this private network for us is actually commented out when you generate a <code>Vagrantfile</code> without the <code>-m</code> option (go ahead and <code>vagrant init</code> in an empty directory to generate it again). The line you want uncommented is:</p><figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Create a private network, which allows host-only access to the machine</span></span><br><span class="line"><span class="comment"># using a specific IP.</span></span><br><span class="line">config.vm.network <span class="string">"private_network"</span>, <span class="symbol">ip:</span> <span class="string">"192.168.33.10"</span></span><br></pre></td></tr></table></figure><p>You could go for a <code>public_network</code> instead, in which case your VM would be accessible from other devices on the network (not just your host), but I’m not sure whether you can set a static IP for the machine with this option. As you can see below, no IP address is given for this option (this means you’d have to stay checking which IP address is assigned to the VM every time you boot it):</p><figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Create a public network, which generally matched to bridged network.</span></span><br><span class="line"><span class="comment"># Bridged networks make the machine appear as another physical device on</span></span><br><span class="line"><span class="comment"># your network.</span></span><br><span class="line"><span class="comment"># config.vm.network "public_network"</span></span><br></pre></td></tr></table></figure><p>After adding the private network, our <code>Vagrantfile</code> looks like this:</p><figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="constant">Vagrant</span>.configure(<span class="number">2</span>) <span class="keyword">do</span> |config|</span><br><span class="line">  config.vm.box = <span class="string">"rails"</span></span><br><span class="line">  config.vm.network <span class="string">"private_network"</span>, <span class="symbol">ip:</span> <span class="string">"192.168.33.10"</span></span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><p>To put this change into effect, you’ll need to restart the VM with <code>vagrant reload</code> (run it in the same directory containing your <code>Vagrantfile</code> in your host OS).</p><p>After logging in again with <code>vagrant ssh</code>, running <code>ifconfig</code> should show us the new IP address. In fact, you should be able to successfully <code>ping 192.168.33.10</code> from the host OS.</p><p>If you now <code>cd</code> into the Rails app, you can start Rails listening on that IP address (or on 0.0.0.0) with: <code>rails s -b 192.168.33.10</code>. After doing this, you should be able to access Rails from your host OS by browsing to <code>http://192.168.33.10:3000/</code>.</p><p>One last thing. If you read the Rails log output after hitting Rails from your host OS’s browser, you’ll find:</p><blockquote><p>Cannot render console from 192.168.33.1! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255</p></blockquote><p>Our guest’s IP address is <code>192.168.33.10</code>, and our host’s is (automatically set to) <code>192.168.33.1</code> i.e. the host’s IP address is the same but with <code>1</code> for the final octet of the address. If you <code>ifconfig | grep -C 2 .33.1</code> on the host OS (assuming you’re on a Unixy host), you’ll verify this (it’s probably <code>ipconfig</code> on Windows). Or you could just <code>ping 192.168.33.1</code> from the guest.</p><p>In any case, Rails seems to be complaining that we’re accessing it from the host (<code>192.168.33.1</code>), but it renders the console just fine in our browser so that message is just noise to us.</p><p>To get rid of it, you can follow the advise in this <a href="http://stackoverflow.com/questions/29417328/how-to-disable-cannot-render-console-from-on-rails" target="_blank" rel="external">SO question</a>, i.e. add this to <code>config/environments/development.rb</code>:</p><figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">config.web_console.whitelisted_ips = <span class="string">'192.168.33.1'</span></span><br></pre></td></tr></table></figure><p>Unfortunately, this is something you’ll need to remember to do everytime you start a new Rails project with this setup.</p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h1 id=&quot;Intro&quot;&gt;&lt;a href=&quot;#Intro&quot; class=&quot;headerlink&quot; title=&quot;Intro&quot;&gt;&lt;/a&gt;Intro&lt;/h1&gt;&lt;p&gt;In this post we’ll see how to create a virtual machine run
      
    
    </summary>
    
      <category term="programming" scheme="http://justincalleja.com/categories/programming/"/>
    
    
      <category term="rails" scheme="http://justincalleja.com/tags/rails/"/>
    
      <category term="ruby" scheme="http://justincalleja.com/tags/ruby/"/>
    
      <category term="vagrant" scheme="http://justincalleja.com/tags/vagrant/"/>
    
  </entry>
  
  <entry>
    <title>Vanilla CSS grid</title>
    <link href="http://justincalleja.com/2015/11/08/vanilla-css-grid/"/>
    <id>http://justincalleja.com/2015/11/08/vanilla-css-grid/</id>
    <published>2015-11-08T00:00:00.000Z</published>
    <updated>2020-04-07T09:25:01.205Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" href="/vanilla-css-grid/css/styles.css"><h1 id="Intro"><a href="#Intro" class="headerlink" title="Intro"></a>Intro</h1><p>Pulling in a CSS framework such as <a href="http://getbootstrap.com/" target="_blank" rel="external">Bootstrap</a>, or even just it’s grid system, can be overkill when all you want is a simple page with a couple of columns in it.</p><p>In this post we’ll be using plain CSS to get some responsive columns on our page, effectively writing a minimal grid system.</p><h1 id="Setting-up-the-markup"><a href="#Setting-up-the-markup" class="headerlink" title="Setting up the markup"></a>Setting up the markup</h1><p>To follow along, you can start with a basic page as shown below:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="doctype">&lt;!DOCTYPE html&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="title">html</span> <span class="attribute">lang</span>=<span class="value">"en"</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="title">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">meta</span> <span class="attribute">charset</span>=<span class="value">"UTF-8"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">meta</span> <span class="attribute">name</span>=<span class="value">"viewport"</span> <span class="attribute">content</span>=<span class="value">"width=device-width"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">title</span>&gt;</span><span class="tag">&lt;/<span class="title">title</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">link</span> <span class="attribute">rel</span>=<span class="value">"stylesheet"</span> <span class="attribute">href</span>=<span class="value">"//cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.css"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">link</span> <span class="attribute">rel</span>=<span class="value">"stylesheet"</span> <span class="attribute">href</span>=<span class="value">"css/styles.css"</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="title">head</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="title">body</span>&gt;</span></span><br><span class="line">    </span><br><span class="line">  <span class="tag">&lt;/<span class="title">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">html</span>&gt;</span></span><br></pre></td></tr></table></figure><p>After pulling in <code>reset.css</code> (to remove inconsistencies in default styles across different browsers), we’re simply linking to our custom styles in <code>styles.css</code>.</p><p>Next, you need to decide on a class name to give to your containing element. Frameworks like Bootstrap use the class name “container” so it’s best to choose another name just in case you later decide to use such a framework. I’ll be using “grid-container”:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="title">div</span> <span class="attribute">class</span>=<span class="value">"grid-container"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">div</span>&gt;</span></span><br></pre></td></tr></table></figure><p>Inside the grid container, we’ll be adding rows as shown in the example below:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="title">div</span> <span class="attribute">class</span>=<span class="value">"row"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">div</span> <span class="attribute">class</span>=<span class="value">"col-xsm"</span>&gt;</span><span class="tag">&lt;<span class="title">p</span>&gt;</span>col-xsm 1. Adipisicing delectus nisi sequi placeat amet! Quasi ullam nulla iure saepe velit eos doloremque facere modi? Consectetur nulla possimus sequi?<span class="tag">&lt;/<span class="title">p</span>&gt;</span><span class="tag">&lt;/<span class="title">div</span>&gt;</span> </span><br><span class="line">    <span class="tag">&lt;<span class="title">div</span> <span class="attribute">class</span>=<span class="value">"col-xsm"</span>&gt;</span><span class="tag">&lt;<span class="title">p</span>&gt;</span>col-xsm 2. Adipisicing delectus nisi sequi placeat amet! Quasi ullam nulla iure saepe velit eos doloremque facere modi? Consectetur nulla possimus sequi?<span class="tag">&lt;/<span class="title">p</span>&gt;</span><span class="tag">&lt;/<span class="title">div</span>&gt;</span> </span><br><span class="line">    <span class="tag">&lt;<span class="title">div</span> <span class="attribute">class</span>=<span class="value">"col-xsm"</span>&gt;</span><span class="tag">&lt;<span class="title">p</span>&gt;</span>col-xsm 3. Adipisicing delectus nisi sequi placeat amet! Quasi ullam nulla iure saepe velit eos doloremque facere modi? Consectetur nulla possimus sequi?<span class="tag">&lt;/<span class="title">p</span>&gt;</span><span class="tag">&lt;/<span class="title">div</span>&gt;</span> </span><br><span class="line">    <span class="tag">&lt;<span class="title">div</span> <span class="attribute">class</span>=<span class="value">"col-xsm"</span>&gt;</span><span class="tag">&lt;<span class="title">p</span>&gt;</span>col-xsm 4. Adipisicing delectus nisi sequi placeat amet! Quasi ullam nulla iure saepe velit eos doloremque facere modi? Consectetur nulla possimus sequi?<span class="tag">&lt;/<span class="title">p</span>&gt;</span><span class="tag">&lt;/<span class="title">div</span>&gt;</span> </span><br><span class="line"><span class="tag">&lt;/<span class="title">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="title">div</span> <span class="attribute">class</span>=<span class="value">"row"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">div</span> <span class="attribute">class</span>=<span class="value">"col-sm"</span>&gt;</span><span class="tag">&lt;<span class="title">p</span>&gt;</span>col-sm 1. Adipisicing delectus nisi sequi placeat amet! Quasi ullam nulla iure saepe velit eos doloremque facere modi? Consectetur nulla possimus sequi?<span class="tag">&lt;/<span class="title">p</span>&gt;</span><span class="tag">&lt;/<span class="title">div</span>&gt;</span> </span><br><span class="line">    <span class="tag">&lt;<span class="title">div</span> <span class="attribute">class</span>=<span class="value">"col-sm"</span>&gt;</span><span class="tag">&lt;<span class="title">p</span>&gt;</span>col-sm 2. Adipisicing delectus nisi sequi placeat amet! Quasi ullam nulla iure saepe velit eos doloremque facere modi? Consectetur nulla possimus sequi?<span class="tag">&lt;/<span class="title">p</span>&gt;</span><span class="tag">&lt;/<span class="title">div</span>&gt;</span> </span><br><span class="line"><span class="tag">&lt;/<span class="title">div</span>&gt;</span></span><br></pre></td></tr></table></figure><p>Here we have 2 rows, the first made up of 4 <em>col-xsm</em> columns, while the second, of 2 <em>col-sm</em> columns.</p><h1 id="Styles"><a href="#Styles" class="headerlink" title="Styles"></a>Styles</h1><p>The first thing we’ll do in our <code>styles.css</code> is target the grid container, as well as anything within it, and set the <code>box-sizing</code> property to <code>border-box</code>:</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="class">.grid-container</span>, <span class="class">.grid-container</span> * <span class="rules">&#123;</span><br><span class="line">  <span class="rule"><span class="attribute">-webkit-box-sizing</span>:<span class="value"> border-box</span></span>;</span><br><span class="line">  <span class="rule"><span class="attribute">-moz-box-sizing</span>:<span class="value"> border-box</span></span>;</span><br><span class="line">  <span class="rule"><span class="attribute">box-sizing</span>:<span class="value"> border-box</span></span>;</span><br><span class="line">&#125;</span></span><br></pre></td></tr></table></figure><p>This will include the padding and border in each element’s total width and height (so later, when we’ll be sepecifying widths in percentages, padding and boarder will be included).</p><p>Targetting the grid container again, we can center it by setting it’s left and right margins to <code>auto</code>. I’m also setting it’s max width to <code>750px</code> here as I’ll be using these styles on this page and that’s the max width of my post content. Feel free to increase this for your purposes. Setting the width to <code>100%</code> means the grid will take up all available space until the viewport reaches a width of 750px, at which point the grid’s width will stop expanding: </p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="class">.grid-container</span> <span class="rules">&#123;</span><br><span class="line">  <span class="rule"><span class="attribute">width</span>:<span class="value"> <span class="number">100%</span></span></span>;</span><br><span class="line">  <span class="rule"><span class="attribute">margin</span>:<span class="value"> <span class="number">0</span> auto</span></span>; </span><br><span class="line">  <span class="rule"><span class="attribute">max-width</span>:<span class="value"> <span class="number">750px</span></span></span>;      </span><br><span class="line">&#125;</span></span><br></pre></td></tr></table></figure><!-- you could add clearfix hack here or add it later after demoing what can happen without it --><p>We’ll now target <em>all</em> our columns using an <a href="http://www.w3.org/TR/selectors/#selectors" target="_blank" rel="external">attribute selector</a> on classes which begin with “col-“. As we’re going to start styling with the smallest viewport in mind, all our columns will be 100% wide (except for <code>col-xsm</code> which will be 50%). Floating our columns to the left will allow us to lay them out as columns on the page, and adding some padding is in order after resetting our styles:</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr_selector">[class^='col-']</span> <span class="rules">&#123;</span><br><span class="line">    <span class="rule"><span class="attribute">float</span>:<span class="value"> left</span></span>; </span><br><span class="line">    <span class="rule"><span class="attribute">width</span>:<span class="value"> <span class="number">100%</span></span></span>;</span><br><span class="line">    <span class="rule"><span class="attribute">padding</span>:<span class="value"> <span class="number">10px</span></span></span>;</span><br><span class="line">&#125;</span></span><br><span class="line"><span class="class">.col-xsm</span> <span class="rules">&#123; <span class="rule"><span class="attribute">width</span>:<span class="value"> <span class="number">50%</span></span></span>; &#125;</span></span><br></pre></td></tr></table></figure><p>Before our first preview, lets go ahead and add an outline around all our elements to get a better idea of the spacing between them:</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="class">.outline</span>, <span class="class">.outline</span> *<span class="rules">&#123;</span><br><span class="line">  <span class="rule"><span class="attribute">outline</span>:<span class="value"> <span class="number">1px</span> solid <span class="hexcolor">#d6d6d6</span></span></span>; </span><br><span class="line">&#125;</span></span><br></pre></td></tr></table></figure><p>At this point, given the HTML below:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="title">div</span> <span class="attribute">class</span>=<span class="value">"grid-container outline"</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="title">div</span> <span class="attribute">class</span>=<span class="value">"row-noclearfix"</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="title">div</span> <span class="attribute">class</span>=<span class="value">"col-xsm"</span>&gt;</span><span class="tag">&lt;<span class="title">p</span>&gt;</span>col-xsm 1. Adipisicing delectus nisi sequi placeat amet! Quasi ullam nulla iure saepe velit eos doloremque facere modi? Consectetur nulla possimus sequi? Sit facilis nulla accusamus veniam at, corrupti cupiditate! Eveniet aliquam aspernatur ipsum vitae molestias similique eum perferendis sunt sit minus. Rem cupiditate optio rem omnis.<span class="tag">&lt;/<span class="title">p</span>&gt;</span><span class="tag">&lt;/<span class="title">div</span>&gt;</span> </span><br><span class="line">      <span class="tag">&lt;<span class="title">div</span> <span class="attribute">class</span>=<span class="value">"col-xsm"</span>&gt;</span><span class="tag">&lt;<span class="title">p</span>&gt;</span>col-xsm 2. Adipisicing delectus nisi sequi placeat amet! Quasi ullam nulla iure saepe velit eos doloremque facere modi? Consectetur nulla possimus sequi?<span class="tag">&lt;/<span class="title">p</span>&gt;</span><span class="tag">&lt;/<span class="title">div</span>&gt;</span> </span><br><span class="line">  <span class="tag">&lt;/<span class="title">div</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="title">div</span> <span class="attribute">class</span>=<span class="value">"row-noclearfix"</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="title">div</span> <span class="attribute">class</span>=<span class="value">"col-xsm"</span>&gt;</span><span class="tag">&lt;<span class="title">p</span>&gt;</span>col-xsm 3. Adipisicing delectus nisi sequi placeat amet! Quasi ullam nulla iure saepe velit eos doloremque facere modi? Consectetur nulla possimus sequi?<span class="tag">&lt;/<span class="title">p</span>&gt;</span><span class="tag">&lt;/<span class="title">div</span>&gt;</span> </span><br><span class="line">      <span class="tag">&lt;<span class="title">div</span> <span class="attribute">class</span>=<span class="value">"col-xsm"</span>&gt;</span><span class="tag">&lt;<span class="title">p</span>&gt;</span>col-xsm 4. Adipisicing delectus nisi sequi placeat amet! Quasi ullam nulla iure saepe velit eos doloremque facere modi? Consectetur nulla possimus sequi?<span class="tag">&lt;/<span class="title">p</span>&gt;</span><span class="tag">&lt;/<span class="title">div</span>&gt;</span> </span><br><span class="line">  <span class="tag">&lt;/<span class="title">div</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="title">div</span> <span class="attribute">class</span>=<span class="value">"row-noclearfix"</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="title">div</span> <span class="attribute">class</span>=<span class="value">"col-sm"</span>&gt;</span><span class="tag">&lt;<span class="title">p</span>&gt;</span>col-sm 1. Adipisicing delectus nisi sequi placeat amet! Quasi ullam nulla iure saepe velit eos doloremque facere modi? Consectetur nulla possimus sequi?<span class="tag">&lt;/<span class="title">p</span>&gt;</span><span class="tag">&lt;/<span class="title">div</span>&gt;</span> </span><br><span class="line">      <span class="tag">&lt;<span class="title">div</span> <span class="attribute">class</span>=<span class="value">"col-sm"</span>&gt;</span><span class="tag">&lt;<span class="title">p</span>&gt;</span>col-sm 2. Adipisicing delectus nisi sequi placeat amet! Quasi ullam nulla iure saepe velit eos doloremque facere modi? Consectetur nulla possimus sequi?<span class="tag">&lt;/<span class="title">p</span>&gt;</span><span class="tag">&lt;/<span class="title">div</span>&gt;</span> </span><br><span class="line">  <span class="tag">&lt;/<span class="title">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">div</span>&gt;</span></span><br></pre></td></tr></table></figure><p>we get something like this:</p><div class="grid-container outline">  <div class="row-noclearfix">      <div class="col-xsm"><p>col-xsm 1. Adipisicing delectus nisi sequi placeat amet! Quasi ullam nulla iure saepe velit eos doloremque facere modi? Consectetur nulla possimus sequi? Sit facilis nulla accusamus veniam at, corrupti cupiditate! Eveniet aliquam aspernatur ipsum vitae molestias similique eum perferendis sunt sit minus. Rem cupiditate optio rem omnis.</p></div>       <div class="col-xsm"><p>col-xsm 2. Adipisicing delectus nisi sequi placeat amet! Quasi ullam nulla iure saepe velit eos doloremque facere modi? Consectetur nulla possimus sequi?</p></div>   </div>  <div class="row-noclearfix">      <div class="col-xsm"><p>col-xsm 3. Adipisicing delectus nisi sequi placeat amet! Quasi ullam nulla iure saepe velit eos doloremque facere modi? Consectetur nulla possimus sequi?</p></div>       <div class="col-xsm"><p>col-xsm 4. Adipisicing delectus nisi sequi placeat amet! Quasi ullam nulla iure saepe velit eos doloremque facere modi? Consectetur nulla possimus sequi?</p></div>   </div>  <div class="row-noclearfix">      <div class="col-sm"><p>col-sm 1. Adipisicing delectus nisi sequi placeat amet! Quasi ullam nulla iure saepe velit eos doloremque facere modi? Consectetur nulla possimus sequi?</p></div>       <div class="col-sm"><p>col-sm 2. Adipisicing delectus nisi sequi placeat amet! Quasi ullam nulla iure saepe velit eos doloremque facere modi? Consectetur nulla possimus sequi?</p></div>   </div></div><div class="clear"><br><p>As you can see, the second row starting with <code>col-xsm</code> 3 is not in place. The reason this is happening is becuase we have not cleared our floats. So in order to fix this, we can add the following <a href="http://nicolasgallagher.com/micro-clearfix-hack/" target="_blank" rel="external">clearfix hack</a>:</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="class">.row</span><span class="pseudo">:before</span>, </span><br><span class="line"><span class="class">.row</span><span class="pseudo">:after</span> <span class="rules">&#123;</span><br><span class="line">    <span class="rule"><span class="attribute">content</span>:<span class="value"><span class="string">" "</span></span></span>;</span><br><span class="line">    <span class="rule"><span class="attribute">display</span>:<span class="value"> table</span></span>;</span><br><span class="line">&#125;</span></span><br><span class="line"><span class="class">.row</span><span class="pseudo">:after</span> <span class="rules">&#123;</span><br><span class="line">    <span class="rule"><span class="attribute">clear</span>:<span class="value">both</span></span>;</span><br><span class="line">&#125;</span></span><br></pre></td></tr></table></figure><p>After changing the row classes back to “row” in the example above, we get the desired effect:</p><div class="grid-container outline">  <div class="row">      <div class="col-xsm"><p>col-xsm 1. Adipisicing delectus nisi sequi placeat amet! Quasi ullam nulla iure saepe velit eos doloremque facere modi? Consectetur nulla possimus sequi? Sit facilis nulla accusamus veniam at, corrupti cupiditate! Eveniet aliquam aspernatur ipsum vitae molestias similique eum perferendis sunt sit minus. Rem cupiditate optio rem omnis.</p></div>       <div class="col-xsm"><p>col-xsm 2. Adipisicing delectus nisi sequi placeat amet! Quasi ullam nulla iure saepe velit eos doloremque facere modi? Consectetur nulla possimus sequi?</p></div>   </div>  <div class="row">      <div class="col-xsm"><p>col-xsm 3. Adipisicing delectus nisi sequi placeat amet! Quasi ullam nulla iure saepe velit eos doloremque facere modi? Consectetur nulla possimus sequi?</p></div>       <div class="col-xsm"><p>col-xsm 4. Adipisicing delectus nisi sequi placeat amet! Quasi ullam nulla iure saepe velit eos doloremque facere modi? Consectetur nulla possimus sequi?</p></div>   </div>  <div class="row">      <div class="col-sm"><p>col-sm 1. Adipisicing delectus nisi sequi placeat amet! Quasi ullam nulla iure saepe velit eos doloremque facere modi? Consectetur nulla possimus sequi?</p></div>       <div class="col-sm"><p>col-sm 2. Adipisicing delectus nisi sequi placeat amet! Quasi ullam nulla iure saepe velit eos doloremque facere modi? Consectetur nulla possimus sequi?</p></div>   </div></div><h2 id="Adding-media-queries"><a href="#Adding-media-queries" class="headerlink" title="Adding media queries"></a>Adding media queries</h2><p>So far we’ve been styling with mobile in mind, which is why we’ve specified all our columns to be 100% wide except for our extra small ones (<code>col-xsm</code>) which are 50% wide. It’s now time to change that, but before doing so, we need to figure out at which breakpoints we want our column widths to change. I’ll be using <code>min-width</code>s of 480px and 768px:</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="at_rule">@<span class="keyword">media</span> screen and (min-width: <span class="number">480px</span>) </span>&#123;</span><br><span class="line">  <span class="class">.grid-container</span><span class="class">.r</span> <span class="rules">&#123;</span><br><span class="line">    <span class="rule"><span class="attribute">background</span>:<span class="value"> tomato</span></span>;</span><br><span class="line">  &#125;</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="at_rule">@<span class="keyword">media</span> screen and (min-width: <span class="number">768px</span>) </span>&#123;</span><br><span class="line">  <span class="class">.grid-container</span><span class="class">.r</span> <span class="rules">&#123;</span><br><span class="line">    <span class="rule"><span class="attribute">background</span>:<span class="value"> tan</span></span>;</span><br><span class="line">  &#125;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>This means something like: “when the browser width is greater than or equal to 480px, apply the styles in the first media query; then when it gets greater or equal to 768px, override/add with the styles in the second media query”.</p><p>You will notice I’m applying the styles only to elements which have both the class of <code>grid-container</code> as well as the class <code>r</code> on them. I’m doing this in order to leave previous examples on this page uneffected, and I’ll be doing the same when making our columns responsive as we go forward. Obviously, you should remove the <code>.r</code> part in your selectors and avoid littering your HTML with these extra classes on your own pages.</p><p>One other thing to note as we go forward. When resizing Chrome with the developer tools open, you will notice “width x height” dimensions given in the top right of the browser. Make sure you’re at 100% zoom of the page if you want the width shown in Chrome to match up to the breakpoints used in your media queries.</p><p>Ok, so lets quickly check that our media queries are working:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="title">div</span> <span class="attribute">class</span>=<span class="value">"grid-container r"</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="title">p</span>&gt;</span>Sit autem iure eum voluptates possimus. Voluptas illo quod dolorem?<span class="tag">&lt;/<span class="title">p</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">div</span>&gt;</span></span><br></pre></td></tr></table></figure><div class="grid-container r">  <p>Sit autem iure eum voluptates possimus. Voluptas illo quod dolorem?</p></div><!-- keep as div followed by br --><div class="clear"><br><p>At a viewport of over 768px wide, you should see the lorem ipsum above with a <code>tan</code> background. At over 480px but less than 768px it should be <code>tomato</code>, and at under 480px neither will apply leaving us back with our mobile styles.</p><p>With that in place, we can go ahead and fill in our desired column widths:</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="at_rule">@<span class="keyword">media</span> screen and (min-width : <span class="number">480px</span>) </span>&#123;</span><br><span class="line">  <span class="class">.grid-container</span><span class="class">.r</span> <span class="rules">&#123;</span><br><span class="line">    <span class="rule"><span class="attribute">background</span>:<span class="value"> tomato</span></span>;</span><br><span class="line">  &#125;</span></span><br><span class="line">  <span class="class">.col-xsm</span><span class="class">.r</span>  <span class="rules">&#123; <span class="rule"><span class="attribute">width</span>:<span class="value"> <span class="number">33.33%</span></span></span>;  &#125;</span></span><br><span class="line">  <span class="class">.col-sm</span><span class="class">.r</span>   <span class="rules">&#123; <span class="rule"><span class="attribute">width</span>:<span class="value"> <span class="number">50%</span></span></span>;     &#125;</span></span><br><span class="line">  <span class="class">.col-md</span><span class="class">.r</span>   <span class="rules">&#123; <span class="rule"><span class="attribute">width</span>:<span class="value"> <span class="number">83.33%</span></span></span>;  &#125;</span></span><br><span class="line">  <span class="class">.col-lg</span><span class="class">.r</span>   <span class="rules">&#123; <span class="rule"><span class="attribute">width</span>:<span class="value"> <span class="number">100%</span></span></span>;    &#125;</span></span><br><span class="line">  <span class="class">.col-xlg</span><span class="class">.r</span>  <span class="rules">&#123; <span class="rule"><span class="attribute">width</span>:<span class="value"> <span class="number">100%</span></span></span>;    &#125;</span></span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="at_rule">@<span class="keyword">media</span> screen and (min-width: <span class="number">768px</span>) </span>&#123;</span><br><span class="line">  <span class="class">.grid-container</span><span class="class">.r</span> <span class="rules">&#123;</span><br><span class="line">    <span class="rule"><span class="attribute">background</span>:<span class="value"> tan</span></span>;</span><br><span class="line">  &#125;</span></span><br><span class="line">  <span class="class">.col-xsm</span><span class="class">.r</span>  <span class="rules">&#123; <span class="rule"><span class="attribute">width</span>:<span class="value"> <span class="number">25%</span></span></span>;  &#125;</span></span><br><span class="line">  <span class="class">.col-sm</span><span class="class">.r</span>   <span class="rules">&#123; <span class="rule"><span class="attribute">width</span>:<span class="value"> <span class="number">33.33%</span></span></span>;     &#125;</span></span><br><span class="line">  <span class="class">.col-md</span><span class="class">.r</span>   <span class="rules">&#123; <span class="rule"><span class="attribute">width</span>:<span class="value"> <span class="number">50%</span></span></span>;  &#125;</span></span><br><span class="line">  <span class="class">.col-lg</span><span class="class">.r</span>   <span class="rules">&#123; <span class="rule"><span class="attribute">width</span>:<span class="value"> <span class="number">83.33%</span></span></span>;    &#125;</span></span><br><span class="line">  <span class="class">.col-xlg</span><span class="class">.r</span>  <span class="rules">&#123; <span class="rule"><span class="attribute">width</span>:<span class="value"> <span class="number">100%</span></span></span>;    &#125;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>We’re setting <code>col-xsm</code> to take up 1/3 of my <code>max-width</code> of 750px (my blog post width) when the viewport’s width is between 480px and 767px inclusive. It’s going to change to be 25% that width when the viewport is 768px wide or wider, and it’s going to go back to 50% when the viewport is 479px wide or less.</p><p>Try changing the browser’s width to see the result in the following:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="title">div</span> <span class="attribute">class</span>=<span class="value">"grid-container r"</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="title">div</span> <span class="attribute">class</span>=<span class="value">"row"</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="title">div</span> <span class="attribute">class</span>=<span class="value">"col-xsm r"</span>&gt;</span><span class="tag">&lt;<span class="title">p</span>&gt;</span>col-xsm 1. Adipisicing delectus nisi sequi placeat amet! Quasi ullam nulla iure saepe velit eos doloremque facere modi? Consectetur nulla possimus sequi? Sit facilis nulla accusamus veniam at, corrupti cupiditate! Eveniet aliquam aspernatur ipsum vitae molestias similique eum perferendis sunt sit minus. Rem cupiditate optio rem omnis.<span class="tag">&lt;/<span class="title">p</span>&gt;</span><span class="tag">&lt;/<span class="title">div</span>&gt;</span> </span><br><span class="line">      <span class="tag">&lt;<span class="title">div</span> <span class="attribute">class</span>=<span class="value">"col-xsm r"</span>&gt;</span><span class="tag">&lt;<span class="title">p</span>&gt;</span>col-xsm 2. Adipisicing delectus nisi sequi placeat amet! Quasi ullam nulla iure saepe velit eos doloremque facere modi? Consectetur nulla possimus sequi?<span class="tag">&lt;/<span class="title">p</span>&gt;</span><span class="tag">&lt;/<span class="title">div</span>&gt;</span> </span><br><span class="line">  <span class="tag">&lt;/<span class="title">div</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="title">div</span> <span class="attribute">class</span>=<span class="value">"row"</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="title">div</span> <span class="attribute">class</span>=<span class="value">"col-sm r"</span>&gt;</span><span class="tag">&lt;<span class="title">p</span>&gt;</span>col-sm 1. Adipisicing delectus nisi sequi placeat amet! Quasi ullam nulla iure saepe velit eos doloremque facere modi? Consectetur nulla possimus sequi? Consectetur alias quos minima quae at! Consequuntur repellendus laboriosam laborum fugiat similique pariatur. Quidem repellat necessitatibus sed saepe voluptatum obcaecati modi maxime cum vero autem. Odit molestiae labore laudantium odit!<span class="tag">&lt;/<span class="title">p</span>&gt;</span><span class="tag">&lt;/<span class="title">div</span>&gt;</span> </span><br><span class="line">      <span class="tag">&lt;<span class="title">div</span> <span class="attribute">class</span>=<span class="value">"col-sm r"</span>&gt;</span><span class="tag">&lt;<span class="title">p</span>&gt;</span>col-sm 2. Adipisicing delectus nisi sequi placeat amet! Quasi ullam nulla iure saepe velit eos doloremque facere modi? Consectetur nulla possimus sequi?<span class="tag">&lt;/<span class="title">p</span>&gt;</span><span class="tag">&lt;/<span class="title">div</span>&gt;</span> </span><br><span class="line">  <span class="tag">&lt;/<span class="title">div</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="title">div</span> <span class="attribute">class</span>=<span class="value">"row"</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="title">div</span> <span class="attribute">class</span>=<span class="value">"col-md r"</span>&gt;</span><span class="tag">&lt;<span class="title">p</span>&gt;</span>col-md 1. Adipisicing delectus nisi sequi placeat amet! Quasi ullam nulla iure saepe velit eos doloremque facere modi? Consectetur nulla possimus sequi? Consectetur alias quos minima quae at! Consequuntur repellendus laboriosam laborum fugiat similique pariatur. Quidem repellat necessitatibus sed saepe voluptatum obcaecati modi maxime cum vero autem. Odit molestiae labore laudantium odit!<span class="tag">&lt;/<span class="title">p</span>&gt;</span><span class="tag">&lt;/<span class="title">div</span>&gt;</span> </span><br><span class="line">  <span class="tag">&lt;/<span class="title">div</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="title">div</span> <span class="attribute">class</span>=<span class="value">"row"</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="title">div</span> <span class="attribute">class</span>=<span class="value">"col-lg r"</span>&gt;</span><span class="tag">&lt;<span class="title">p</span>&gt;</span>col-lg 1. Adipisicing delectus nisi sequi placeat amet! Quasi ullam nulla iure saepe velit eos doloremque facere modi? Consectetur nulla possimus sequi? Consectetur alias quos minima quae at! Consequuntur repellendus laboriosam laborum fugiat similique pariatur. Quidem repellat necessitatibus sed saepe voluptatum obcaecati modi maxime cum vero autem. Odit molestiae labore laudantium odit!<span class="tag">&lt;/<span class="title">p</span>&gt;</span><span class="tag">&lt;/<span class="title">div</span>&gt;</span> </span><br><span class="line">  <span class="tag">&lt;/<span class="title">div</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="title">div</span> <span class="attribute">class</span>=<span class="value">"row"</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="title">div</span> <span class="attribute">class</span>=<span class="value">"col-xlg r"</span>&gt;</span><span class="tag">&lt;<span class="title">p</span>&gt;</span>col-xlg 1. Adipisicing delectus nisi sequi placeat amet! Quasi ullam nulla iure saepe velit eos doloremque facere modi? Consectetur nulla possimus sequi? Consectetur alias quos minima quae at! Consequuntur repellendus laboriosam laborum fugiat similique pariatur. Quidem repellat necessitatibus sed saepe voluptatum obcaecati modi maxime cum vero autem. Odit molestiae labore laudantium odit!<span class="tag">&lt;/<span class="title">p</span>&gt;</span><span class="tag">&lt;/<span class="title">div</span>&gt;</span> </span><br><span class="line">  <span class="tag">&lt;/<span class="title">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">div</span>&gt;</span></span><br></pre></td></tr></table></figure><div class="grid-container r">  <div class="row">      <div class="col-xsm r"><p>col-xsm 1. Adipisicing delectus nisi sequi placeat amet! Quasi ullam nulla iure saepe velit eos doloremque facere modi? Consectetur nulla possimus sequi? Sit facilis nulla accusamus veniam at, corrupti cupiditate! Eveniet aliquam aspernatur ipsum vitae molestias similique eum perferendis sunt sit minus. Rem cupiditate optio rem omnis.</p></div>       <div class="col-xsm r"><p>col-xsm 2. Adipisicing delectus nisi sequi placeat amet! Quasi ullam nulla iure saepe velit eos doloremque facere modi? Consectetur nulla possimus sequi?</p></div>   </div>  <div class="row">      <div class="col-sm r"><p>col-sm 1. Adipisicing delectus nisi sequi placeat amet! Quasi ullam nulla iure saepe velit eos doloremque facere modi? Consectetur nulla possimus sequi? Consectetur alias quos minima quae at! Consequuntur repellendus laboriosam laborum fugiat similique pariatur. Quidem repellat necessitatibus sed saepe voluptatum obcaecati modi maxime cum vero autem. Odit molestiae labore laudantium odit!</p></div>       <div class="col-sm r"><p>col-sm 2. Adipisicing delectus nisi sequi placeat amet! Quasi ullam nulla iure saepe velit eos doloremque facere modi? Consectetur nulla possimus sequi?</p></div>   </div>  <div class="row">      <div class="col-md r"><p>col-md 1. Adipisicing delectus nisi sequi placeat amet! Quasi ullam nulla iure saepe velit eos doloremque facere modi? Consectetur nulla possimus sequi? Consectetur alias quos minima quae at! Consequuntur repellendus laboriosam laborum fugiat similique pariatur. Quidem repellat necessitatibus sed saepe voluptatum obcaecati modi maxime cum vero autem. Odit molestiae labore laudantium odit!</p></div>   </div>  <div class="row">      <div class="col-lg r"><p>col-lg 1. Adipisicing delectus nisi sequi placeat amet! Quasi ullam nulla iure saepe velit eos doloremque facere modi? Consectetur nulla possimus sequi? Consectetur alias quos minima quae at! Consequuntur repellendus laboriosam laborum fugiat similique pariatur. Quidem repellat necessitatibus sed saepe voluptatum obcaecati modi maxime cum vero autem. Odit molestiae labore laudantium odit!</p></div>   </div>  <div class="row">      <div class="col-xlg r"><p>col-xlg 1. Adipisicing delectus nisi sequi placeat amet! Quasi ullam nulla iure saepe velit eos doloremque facere modi? Consectetur nulla possimus sequi? Consectetur alias quos minima quae at! Consequuntur repellendus laboriosam laborum fugiat similique pariatur. Quidem repellat necessitatibus sed saepe voluptatum obcaecati modi maxime cum vero autem. Odit molestiae labore laudantium odit!</p></div>   </div></div><div class="clear"><br></div></div></div>]]></content>
    
    <summary type="html">
    
      
      
        &lt;link rel=&quot;stylesheet&quot; href=&quot;/vanilla-css-grid/css/styles.css&quot;&gt;

&lt;h1 id=&quot;Intro&quot;&gt;&lt;a href=&quot;#Intro&quot; class=&quot;headerlink&quot; title=&quot;Intro&quot;&gt;&lt;/a&gt;Intro&lt;
      
    
    </summary>
    
      <category term="programming" scheme="http://justincalleja.com/categories/programming/"/>
    
    
      <category term="css" scheme="http://justincalleja.com/tags/css/"/>
    
  </entry>
  
  <entry>
    <title>War in jar with Maven</title>
    <link href="http://justincalleja.com/2015/04/28/war-in-jar/"/>
    <id>http://justincalleja.com/2015/04/28/war-in-jar/</id>
    <published>2015-04-28T00:00:00.000Z</published>
    <updated>2020-04-07T09:25:01.206Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Intro"><a href="#Intro" class="headerlink" title="Intro"></a>Intro</h1><p>The following is one way you could go about packaging a war file in a jar file with <a href="https://maven.apache.org/ &quot;Maven" target="_blank" rel="external">Maven</a>. You might want to do this if you’re loading a war file from the classpath programmatically.</p><p>For instance, assuming you had <em>myjar.jar</em> on the classpath and <em>myjar.jar</em> contained <em>mywar.war</em>, then you could refer to this war like so: <code>classpath://mywar.war</code>. Simply adding the directory containing your war file on the classpath (as you would to pick up <em>*.class</em> files) would <em>not</em> be enough to get a similar result.</p><h1 id="By-example"><a href="#By-example" class="headerlink" title="By example"></a>By example</h1><p>To get something to work with, we can make use of the <code>maven-archetype-webapp</code> archetype:</p><figure class="highlight haml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">$ mvn archetype:create  \</span><br><span class="line">  -<span class="ruby"><span class="constant">DgroupId</span>=com.tmp \</span><br><span class="line"></span>  -<span class="ruby"><span class="constant">DartifactId</span>=warinjar \</span><br><span class="line"></span>  -<span class="ruby"><span class="constant">DarchetypeArtifactId</span>=maven-archetype-webapp</span><br><span class="line"></span>$ cd warinjar</span><br></pre></td></tr></table></figure><p>Open up <code>pom.xml</code> in the generated project and change the <code>packaging</code> to <code>jar</code>:</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="title">packaging</span>&gt;</span>jar<span class="tag">&lt;/<span class="title">packaging</span>&gt;</span></span><br></pre></td></tr></table></figure><p>The final ingredient is to get the <code>maven-war-plugin</code> in on the action:</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">...</span><br><span class="line"><span class="tag">&lt;<span class="title">build</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">finalName</span>&gt;</span>warinjar<span class="tag">&lt;/<span class="title">finalName</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">plugins</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">plugin</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="title">groupId</span>&gt;</span>org.apache.maven.plugins<span class="tag">&lt;/<span class="title">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="title">artifactId</span>&gt;</span>maven-war-plugin<span class="tag">&lt;/<span class="title">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="title">version</span>&gt;</span>2.6<span class="tag">&lt;/<span class="title">version</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="title">configuration</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="title">outputDirectory</span>&gt;</span>$&#123;project.build.directory&#125;/classes<span class="tag">&lt;/<span class="title">outputDirectory</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="title">configuration</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="title">executions</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="title">execution</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="title">id</span>&gt;</span>build-war-in-classes<span class="tag">&lt;/<span class="title">id</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="title">phase</span>&gt;</span>prepare-package<span class="tag">&lt;/<span class="title">phase</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="title">goals</span>&gt;</span></span><br><span class="line">                        <span class="tag">&lt;<span class="title">goal</span>&gt;</span>war<span class="tag">&lt;/<span class="title">goal</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;/<span class="title">goals</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;/<span class="title">execution</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="title">executions</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="title">plugin</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="title">plugins</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">build</span>&gt;</span></span><br><span class="line">...</span><br></pre></td></tr></table></figure><p>By setting the output directory to <code>${project.build.directory}/classes</code>, this plugin will generate <code>warinjar.war</code> in our <code>target/classes</code> directory, the contents of which are picked up when packaging our project (since we set the packaging to jar above).</p><p>Running <code>mvn clean package</code> will clean out previous build (by deleting the <code>target</code> directory). It will also execute <code>maven-war-plugin</code>‘s <code>war</code> goal since we’re executing it in the <code>prepare-package</code> lifecycle phase (which happens right before the <code>package</code> phase in <a href="https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html#Lifecycle_Reference" title="Maven default lifecycle" target="_blank" rel="external">Maven’s default lifecycle</a>).</p><p>This gives us <code>target/classes/warinjar.war</code> which then gets picked up when producing <code>target/warinjar.jar</code> (have a look at the jar’s contents).</p><p>Of course, you could add another execution to also generate a war outside the jar:</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">...</span><br><span class="line"><span class="tag">&lt;<span class="title">execution</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">id</span>&gt;</span>build-war<span class="tag">&lt;/<span class="title">id</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">phase</span>&gt;</span>package<span class="tag">&lt;/<span class="title">phase</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">configuration</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">outputDirectory</span>&gt;</span>$&#123;project.build.directory&#125;<span class="tag">&lt;/<span class="title">outputDirectory</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">warName</span>&gt;</span>waroutjar<span class="tag">&lt;/<span class="title">warName</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="title">configuration</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">goals</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">goal</span>&gt;</span>war<span class="tag">&lt;/<span class="title">goal</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="title">goals</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">execution</span>&gt;</span></span><br><span class="line">...</span><br></pre></td></tr></table></figure><p>Note that we need to overwrite the plugin’s configuration for this execution. Have a look at the <a href="https://maven.apache.org/plugins/maven-war-plugin/war-mojo.html" title="maven-war-plugin war-mojo" target="_blank" rel="external">documentation</a> page for default values.</p><p>Basically, we’re overwriting the default <code>outputDirectory</code> in our plugin’s configuration, and so, the execution with id <code>build-war-in-classes</code> will output <code>${project.build.finalName}.war</code> (i.e. <em>warinjar.war</em>) to <code>${project.build.directory}/classes</code>.</p><p>Had we not overwritten the configuration in the plugin’s execution with id <code>build-war</code>, we would have basically overwritten <code>target/classes/warinjar.war</code> with itself.</p><p>The final pom file looks like this:</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="title">project</span> <span class="attribute">xmlns</span>=<span class="value">"http://maven.apache.org/POM/4.0.0"</span> <span class="attribute">xmlns:xsi</span>=<span class="value">"http://www.w3.org/2001/XMLSchema-instance"</span></span><br><span class="line">    <span class="attribute">xsi:schemaLocation</span>=<span class="value">"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">modelVersion</span>&gt;</span>4.0.0<span class="tag">&lt;/<span class="title">modelVersion</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">groupId</span>&gt;</span>com.tmp<span class="tag">&lt;/<span class="title">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">artifactId</span>&gt;</span>warinjar<span class="tag">&lt;/<span class="title">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">packaging</span>&gt;</span>jar<span class="tag">&lt;/<span class="title">packaging</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">version</span>&gt;</span>1.0-SNAPSHOT<span class="tag">&lt;/<span class="title">version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">build</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">finalName</span>&gt;</span>warinjar<span class="tag">&lt;/<span class="title">finalName</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">plugins</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="title">plugin</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="title">groupId</span>&gt;</span>org.apache.maven.plugins<span class="tag">&lt;/<span class="title">groupId</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="title">artifactId</span>&gt;</span>maven-war-plugin<span class="tag">&lt;/<span class="title">artifactId</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="title">version</span>&gt;</span>2.6<span class="tag">&lt;/<span class="title">version</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="title">configuration</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="title">outputDirectory</span>&gt;</span>$&#123;project.build.directory&#125;/classes<span class="tag">&lt;/<span class="title">outputDirectory</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;/<span class="title">configuration</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="title">executions</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="title">execution</span>&gt;</span></span><br><span class="line">                        <span class="tag">&lt;<span class="title">id</span>&gt;</span>build-war-in-classes<span class="tag">&lt;/<span class="title">id</span>&gt;</span></span><br><span class="line">                        <span class="tag">&lt;<span class="title">phase</span>&gt;</span>prepare-package<span class="tag">&lt;/<span class="title">phase</span>&gt;</span></span><br><span class="line">                        <span class="tag">&lt;<span class="title">goals</span>&gt;</span></span><br><span class="line">                            <span class="tag">&lt;<span class="title">goal</span>&gt;</span>war<span class="tag">&lt;/<span class="title">goal</span>&gt;</span></span><br><span class="line">                        <span class="tag">&lt;/<span class="title">goals</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;/<span class="title">execution</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="title">execution</span>&gt;</span></span><br><span class="line">                        <span class="tag">&lt;<span class="title">id</span>&gt;</span>build-war<span class="tag">&lt;/<span class="title">id</span>&gt;</span></span><br><span class="line">                        <span class="tag">&lt;<span class="title">phase</span>&gt;</span>package<span class="tag">&lt;/<span class="title">phase</span>&gt;</span></span><br><span class="line">                        <span class="tag">&lt;<span class="title">configuration</span>&gt;</span></span><br><span class="line">                            <span class="tag">&lt;<span class="title">outputDirectory</span>&gt;</span>$&#123;project.build.directory&#125;<span class="tag">&lt;/<span class="title">outputDirectory</span>&gt;</span></span><br><span class="line">                            <span class="tag">&lt;<span class="title">warName</span>&gt;</span>waroutjar<span class="tag">&lt;/<span class="title">warName</span>&gt;</span></span><br><span class="line">                        <span class="tag">&lt;/<span class="title">configuration</span>&gt;</span></span><br><span class="line">                        <span class="tag">&lt;<span class="title">goals</span>&gt;</span></span><br><span class="line">                            <span class="tag">&lt;<span class="title">goal</span>&gt;</span>war<span class="tag">&lt;/<span class="title">goal</span>&gt;</span></span><br><span class="line">                        <span class="tag">&lt;/<span class="title">goals</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;/<span class="title">execution</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;/<span class="title">executions</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="title">plugin</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="title">plugins</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="title">build</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">project</span>&gt;</span></span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h1 id=&quot;Intro&quot;&gt;&lt;a href=&quot;#Intro&quot; class=&quot;headerlink&quot; title=&quot;Intro&quot;&gt;&lt;/a&gt;Intro&lt;/h1&gt;&lt;p&gt;The following is one way you could go about packaging a wa
      
    
    </summary>
    
      <category term="programming" scheme="http://justincalleja.com/categories/programming/"/>
    
    
      <category term="java" scheme="http://justincalleja.com/tags/java/"/>
    
      <category term="maven" scheme="http://justincalleja.com/tags/maven/"/>
    
  </entry>
  
  <entry>
    <title>Sequential control flow with Lo-Dash or Underscore.js</title>
    <link href="http://justincalleja.com/2015/03/08/sequential-control-flow-with-lodash-or-underscore/"/>
    <id>http://justincalleja.com/2015/03/08/sequential-control-flow-with-lodash-or-underscore/</id>
    <published>2015-03-08T00:00:00.000Z</published>
    <updated>2020-04-07T09:25:01.194Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Intro"><a href="#Intro" class="headerlink" title="Intro"></a>Intro</h1><p>This post is based on <a href="http://daemon.co.za/2012/04/simple-async-with-only-underscore/" title="Simple async with only underscore" target="_blank" rel="external">Simple async with only underscore</a> by <a href="http://daemon.co.za/portfolio/" title="Adrian Rossouw" target="_blank" rel="external">Adrian Rossouw</a>. Yes, I did read the following disclaimer regarding this approach:</p><blockquote><p>I don’t recommend this approach much anymore, because I have come to the conclusion that the async.js module is by far the best tool for the job</p><footer><cite><a href="http://daemon.co.za/2012/04/simple-async-with-only-underscore/" target="_blank" rel="external">Simple async with only underscore</a></cite></footer></blockquote><p>It’s hard to disagree with that. <a href="https://github.com/caolan/async" title="async.js" target="_blank" rel="external">Async.js</a> is specifically designed to cater for asynchronous control flow. However, I think there is value in using the approach suggested by Adrian when you’re already depending on <a href="https://lodash.com/" title="Lo-Dash" target="_blank" rel="external">Lo-Dash</a>/<a href="http://underscorejs.org/" title="Underscore.js" target="_blank" rel="external">Underscore.js</a> and do not want to bring in a separate library to handle a one-off control flow need.</p><p>In this post I’ll be explaining the suggested solution in more detail. But before doing that, I will give some background so you might want to skip over to <a href="#toc_2">The approach</a> if you’re already familiar with the need for asynchronous control flow in Node.js / <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop" title="event loop" target="_blank" rel="external">event loop</a> environments.</p><h1 id="The-need"><a href="#The-need" class="headerlink" title="The need"></a>The need</h1><h2 id="Sync-vs-Async-in-a-single-threaded-environment"><a href="#Sync-vs-Async-in-a-single-threaded-environment" class="headerlink" title="Sync vs Async in a single threaded environment"></a>Sync vs Async in a single threaded environment</h2><p>So what’s this all about? Lets set up an example. In an empty directory do the following:</p><ul><li><code>npm i inquirer</code></li><li><code>vim index.js</code></li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> inquirer = <span class="built_in">require</span>(<span class="string">"inquirer"</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> questions = [</span><br><span class="line">  &#123;</span><br><span class="line">    type: <span class="string">"input"</span>,</span><br><span class="line">    name: <span class="string">"username"</span>,</span><br><span class="line">    message: <span class="string">"Enter username"</span></span><br><span class="line">  &#125;,</span><br><span class="line">  &#123;</span><br><span class="line">    type: <span class="string">"password"</span>,</span><br><span class="line">    name: <span class="string">"password"</span>,</span><br><span class="line">    message: <span class="string">"Enter password"</span></span><br><span class="line">  &#125;,</span><br><span class="line">];</span><br><span class="line"></span><br><span class="line">inquirer.prompt(questions, <span class="function"><span class="keyword">function</span>(<span class="params"> answers </span>) </span>&#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">"answers were:"</span>, answers);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">"I want this to be done after prompt"</span>);</span><br></pre></td></tr></table></figure><p><img src="seq-fail.png" alt="Sequential execution fail" title="Sequential execution fail"></p><p>Nevermind the duplicate “Enter username” prompt - notice that the final <code>console.log</code> statement executed before <code>inquirer.prompt</code> was done.</p><p>The code above assumes that expressing the two function invocations in sequence implies sequential execution. In other (multi-threaded) environments, where threads block on I/O, this is a reasonable assumption to make. In these environments, context switching allows one thread to block on I/O, switch over to another thread to keep processing, and switch back when data to process becomes available from the I/O source in question.</p><p>In a single threaded environment, however, you generally don’t <em>want</em> to block. For example, imagine uploading a couple of files from a web application. You wouldn’t want to “stop the world” while this data is still in transit. Instead, you would want to keep processing - for e.g. the user’s input when they decide to stop the upload.</p><p>So we can agree that blocking is not what we generally want to do in a single threaded environment. In the user prompt example above, you do not expect <code>inquirer.prompt</code> to “stop the world” while it fetches data from the user via <a href="http://nodejs.org/api/process.html#process_process_stdin" title="process.stdin" target="_blank" rel="external">process.stdin</a>. The code <code>inquirer.prompt</code> uses to get data from the user does so in an asynchronous manner. It <em>could</em> do the same thing in a synchronous manner instead, but that is not good manners in a single threaded environment. If <code>inquirer.prompt</code> fetched its data synchronously and returned it, then the code above would work as expected but <code>inquirer</code> is not that selfish. It will wait on the stack for data to come in, allowing the processor to go do something useful in the meantime.</p><p>For instance, if we replaced user prompting with a function which reads from disk in a synchronous manner then we get something like this:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> fs = <span class="built_in">require</span>(<span class="string">"fs"</span>);</span><br><span class="line"><span class="keyword">var</span> path = <span class="built_in">require</span>(<span class="string">"path"</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> data = fs.readFileSync(path.resolve(__dirname, __filename), <span class="string">"utf-8"</span>);</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">"I want this to be done after readFileSync\n"</span>, data);</span><br></pre></td></tr></table></figure><p><img src="sync-file-read.png" alt="Sync file reading" title="Sync file reading"></p><p>To summarize, the key points are:</p><ul><li>In a single threaded environment asynchronous I/O becomes essential if you want concurrency.</li><li>If you have statements which execute asynchronously, the order in which you write your statements does not imply the order in which these statements are executed.</li></ul><p>OK, so we know asynchronous I/O is important here, but the order of execution is something we need control over as sometimes we don’t really care, but sometimes there’s no way around it. This means that we need to be able to express sequential execution when it matters - i.e. “do this <em>after</em> that”. If the order of statements won’t cut it, what will?</p><h2 id="Callbacks"><a href="#Callbacks" class="headerlink" title="Callbacks"></a>Callbacks</h2><p>Well, if the order of statements won’t cut it, maybe callbacks, events, Promises, ES6 Generators, or 3rd party libraries such as <a href="https://github.com/caolan/async" title="async.js" target="_blank" rel="external">Async.js</a> will? As you can see, there’s no shortage of tools to use. Let’s pick callbacks and see where that leads us.</p><p>A callback is a function used to effect control flow. You generally pass a callback function to another function which is expected to perform some asynchronous operation and call the callback with the result of the asynchronous operation. This effectively adds another frame on the stack which needs to be cleared before the async-op-performing function itself is removed from the stack.</p><p>If you take another look at <code>inquirer.prompt</code> above, you will see an example of callback usage. The second argument <code>inquirer.prompt</code> takes is a callback function which itself takes an argument which contains the data <code>inquirer.prompt</code> fetched from the user.</p><p>Callbacks are nice, until they aren’t. You might have heard the term “callback hell”, but in any case, here’s a quick look down the abyss:</p><p><img src="http://seajones.co.uk/content/images/2014/12/callback-hell.png" alt="callback hell" title="callback hell"></p><p>Pretty isn’t it?</p><p>The point here isn’t that you shouldn’t use callbacks - it’s that you should be careful not to overuse them. Mixu puts it nicely in his online <a href="http://book.mixu.net/node/ch7.html" title="Mixu&#39;s Node book" target="_blank" rel="external">Node book</a>:</p><blockquote><p>When you start coding with Node.js, it’s a bit like learning programming the first time. Since you want everything to be asynchronous, you use a lot of callbacks without really thinking about how you should structure your code. It’s a bit like being overexcited about the if statement, and using it and only it to write complex programs.</p><footer><cite><a href="http://book.mixu.net/node/ch7.html" target="_blank" rel="external">Mixu’s Node book</a></cite></footer></blockquote><p>OK, so with the background taken care of, let’s move on to one approach we can take to mitigate callback hell by using <a href="https://lodash.com/" title="Lo-Dash" target="_blank" rel="external">Lo-Dash</a>/<a href="http://underscorejs.org/" title="Underscore.js" target="_blank" rel="external">Underscore.js</a>, something you’re likely to already be depending on.</p><h1 id="The-approach"><a href="#The-approach" class="headerlink" title="The approach"></a>The approach</h1><p>To start off with, consider the snippet used in <a href="http://daemon.co.za/2012/04/simple-async-with-only-underscore/" title="Simple async control flow using only underscore.js" target="_blank" rel="external">Adrian’s post</a>:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// generate a callback</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">cb</span>(<span class="params">text</span>) </span>&#123; </span><br><span class="line">    <span class="keyword">return</span> <span class="function"><span class="keyword">function</span>(<span class="params">next</span>) </span>&#123; </span><br><span class="line">        <span class="built_in">console</span>.warn(text); </span><br><span class="line">        next();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// a list of things to call</span></span><br><span class="line"><span class="keyword">var</span> actions = [ cb(<span class="number">1</span>), cb(<span class="number">2</span>), cb(<span class="number">3</span>), cb(<span class="number">4</span>) ]</span><br><span class="line"></span><br><span class="line"><span class="comment">// call the functions in the series array in order</span></span><br><span class="line">_(actions).reduceRight(_.wrap, <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123; <span class="built_in">console</span>.warn(<span class="string">'done'</span>) &#125;)(); </span><br><span class="line"></span><br><span class="line"><span class="comment">// prints out:</span></span><br><span class="line"><span class="comment">// ---</span></span><br><span class="line"><span class="comment">// 1</span></span><br><span class="line"><span class="comment">// 2</span></span><br><span class="line"><span class="comment">// 3</span></span><br><span class="line"><span class="comment">// 4</span></span><br><span class="line"><span class="comment">// done</span></span><br></pre></td></tr></table></figure><p>The general idea is to store the functions you want to have execute sequentially in an array (<code>actions</code>) and use <a href="http://underscorejs.org/#reduceRight" title="reduceRight" target="_blank" rel="external">reduceRight</a> and <a href="http://underscorejs.org/#wrap" title="wrap" target="_blank" rel="external">wrap</a> to give you back a function which you can invoke to kick off the sequential execution of the functions in <code>actions</code>.</p><p>That’s the general idea. Let’s start breaking things down. (Note: I am quoting bits and pieces from the <a href="https://lodash.com/docs" title="Lo-Dash docs" target="_blank" rel="external">Lo-Dash docs</a> below).</p><h2 id="reduce"><a href="#reduce" class="headerlink" title="_.reduce"></a>_.reduce</h2><blockquote><p>_.reduce(collection, [iteratee=_.identity], [accumulator], [thisArg])</p></blockquote><p>This tells us that <code>_.reduce</code> can take 4 arguments, the <code>collection</code> to iterate over, the <code>iteratee</code> function, the <code>accumulator</code> which is the initial value the “reduction” starts with, and <code>thisArg</code> which is the <code>this</code> binding of <code>iteratee</code>.</p><blockquote><p>The <code>iteratee</code> is bound to <code>thisArg</code> and invoked with four arguments; (accumulator, value, index|key, collection). </p></blockquote><p>So apart from knowing what <code>_.reduce</code> takes, you’ll also need to know what the <code>iteratee</code> function takes. </p><ol><li><blockquote><p>If <code>accumulator</code> is not provided the first element of collection is used as the initial value.</p></blockquote><p>This is referring to <code>_.reduce</code>‘s 3rd argument. If you don’t supply an argument, then the first element of <code>collection</code> will be used as the 1st argument in <code>iteratee</code>‘s first invocation.</p></li><li><p><code>iteratee</code>‘s 2nd argument is <code>value</code>, i.e. it’s the next value in <code>collection</code> which hasn’t yet been through <code>iteratee</code>.</p></li><li><p><code>iteratee</code>‘s 3rd argument is the <strong>index</strong> of <code>value</code> in the <code>collection</code> (“index” when the <code>collection</code> is an array, or “key” when the <code>collection</code> is an object).</p></li><li><p><code>iteratee</code>‘s 4th argument is the <code>collection</code> itself (i.e. <code>_.reduce</code>‘s first argument).</p></li></ol><p>Here’s a look at <code>_.reduce</code> in action:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> _ = <span class="built_in">require</span>(<span class="string">"lodash"</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> nums = [<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>];</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">sum</span>(<span class="params">accumulator, value, index, collection</span>) </span>&#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">"acc"</span>, accumulator, <span class="string">"value"</span>, value, <span class="string">"index"</span>, index, <span class="string">"collection"</span>, collection);</span><br><span class="line">  <span class="keyword">return</span> accumulator + value;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> fromFirstEl = _.reduce(nums, sum);</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">"fromFirstEl:"</span>, fromFirstEl);</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> from5 = _.reduce(nums, sum, <span class="number">5</span>);</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">"from5:"</span>, from5);</span><br><span class="line"></span><br><span class="line"><span class="comment">// acc 1 value 2 index 1 collection [ 1, 2, 3, 4, 5 ]</span></span><br><span class="line"><span class="comment">// acc 3 value 3 index 2 collection [ 1, 2, 3, 4, 5 ]</span></span><br><span class="line"><span class="comment">// acc 6 value 4 index 3 collection [ 1, 2, 3, 4, 5 ]</span></span><br><span class="line"><span class="comment">// acc 10 value 5 index 4 collection [ 1, 2, 3, 4, 5 ]</span></span><br><span class="line"><span class="comment">// fromFirstEl: 15</span></span><br><span class="line"><span class="comment">// acc 5 value 1 index 0 collection [ 1, 2, 3, 4, 5 ]</span></span><br><span class="line"><span class="comment">// acc 6 value 2 index 1 collection [ 1, 2, 3, 4, 5 ]</span></span><br><span class="line"><span class="comment">// acc 8 value 3 index 2 collection [ 1, 2, 3, 4, 5 ]</span></span><br><span class="line"><span class="comment">// acc 11 value 4 index 3 collection [ 1, 2, 3, 4, 5 ]</span></span><br><span class="line"><span class="comment">// acc 15 value 5 index 4 collection [ 1, 2, 3, 4, 5 ]</span></span><br><span class="line"><span class="comment">// from5: 20</span></span><br></pre></td></tr></table></figure><p>Notice how the value returned from the <code>iteratee</code> function (i.e. <code>sum</code>) becomes the <code>iteratee</code>‘s <code>accumulator</code> the next time it is invoked on the next item in the <code>collection</code>.</p><p>Also notice how, in the case of no initial <code>accumulator</code>, it’s as if <code>nums</code> is one element short, and the element taken out of <code>nums</code> is used as the initial <code>accumulator</code>.</p><p><code>_.reduceRight</code> is the exact operation but in reverse:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> rightFrom10 = _.reduceRight(nums, sum, <span class="number">10</span>);</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">"rightFrom10:"</span>, rightFrom10);</span><br><span class="line"></span><br><span class="line"><span class="comment">// acc 10 value 5 index 4 collection [ 1, 2, 3, 4, 5 ]</span></span><br><span class="line"><span class="comment">// acc 15 value 4 index 3 collection [ 1, 2, 3, 4, 5 ]</span></span><br><span class="line"><span class="comment">// acc 19 value 3 index 2 collection [ 1, 2, 3, 4, 5 ]</span></span><br><span class="line"><span class="comment">// acc 22 value 2 index 1 collection [ 1, 2, 3, 4, 5 ]</span></span><br><span class="line"><span class="comment">// acc 24 value 1 index 0 collection [ 1, 2, 3, 4, 5 ]</span></span><br><span class="line"><span class="comment">// rightFrom10: 25</span></span><br></pre></td></tr></table></figure><p>So basically, we now know that <code>_.reduce</code> is a function which takes a collection and reduces the values in that collection to a single value based on the logic in its given <code>iteratee</code>.</p><h2 id="wrap"><a href="#wrap" class="headerlink" title="_.wrap"></a>_.wrap</h2><p>Let’s now turn our attention to <a href="https://lodash.com/docs#wrap" title="wrap" target="_blank" rel="external">wrap</a>.</p><blockquote><p>_.wrap(value, wrapper)</p></blockquote><blockquote><p>Creates a function that provides <code>value</code> to the <code>wrapper</code> function as its first argument. Any additional arguments provided to the function are appended to those provided to the wrapper function. The wrapper is invoked with the <code>this</code> binding of the created function.</p></blockquote><p>An example is probably better (based off of <a href="http://underscorejs.org/#wrap" title="Underscore.js doc" target="_blank" rel="external">Underscore.js’s doc</a> as I felt it was easier than the one given in Lo-Dash’s):</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> _ = <span class="built_in">require</span>(<span class="string">"lodash"</span>);</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">hello</span>(<span class="params">name, surname</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="string">"hello: "</span> + name + (surname ? <span class="string">" "</span> + surname : <span class="string">""</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> wrappedHello = _.wrap(hello, <span class="function"><span class="keyword">function</span>(<span class="params">func</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="string">"before, "</span> + func(<span class="string">"moe"</span>) + <span class="string">", after"</span>;</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(wrappedHello());</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> wrappedHello2 = _.wrap(hello, <span class="function"><span class="keyword">function</span>(<span class="params">func, name</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="string">"before, "</span> + func(name) + <span class="string">", after"</span>;</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(wrappedHello2(<span class="string">"joe"</span>));</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> wrappedHello3 = _.wrap(hello, <span class="function"><span class="keyword">function</span>(<span class="params">func, name, surname</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="string">"before, "</span> + func(name, surname) + <span class="string">", after"</span>;</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(wrappedHello3(<span class="string">"joe"</span>, <span class="string">"doe"</span>));</span><br><span class="line"></span><br><span class="line"><span class="comment">// before, hello: moe, after</span></span><br><span class="line"><span class="comment">// before, hello: joe, after</span></span><br><span class="line"><span class="comment">// before, hello: joe doe, after</span></span><br></pre></td></tr></table></figure><p>Essentially, <code>wrap</code> takes the first argument given to it and passes it to it’s second argument which is expected to be the wrapper function (in which you can do any logic around <code>value</code>). Any arguments you pass to the created wrapper functions (e.g. <code>wrappedHello2</code>) get passed as arguments to the <code>wrapper</code> function used in <code>_.wrap</code>.</p><h2 id="Putting-it-all-together"><a href="#Putting-it-all-together" class="headerlink" title="Putting it all together"></a>Putting it all together</h2><p>Revisiting Adrian’s example:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">cb</span>(<span class="params">text</span>) </span>&#123; </span><br><span class="line">    <span class="keyword">return</span> <span class="function"><span class="keyword">function</span>(<span class="params">next</span>) </span>&#123; </span><br><span class="line">        <span class="built_in">console</span>.warn(text); </span><br><span class="line">        next();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// a list of things to call</span></span><br><span class="line"><span class="keyword">var</span> actions = [ cb(<span class="number">1</span>), cb(<span class="number">2</span>), cb(<span class="number">3</span>), cb(<span class="number">4</span>) ]</span><br><span class="line"></span><br><span class="line"><span class="comment">// call the functions in the series array in order</span></span><br><span class="line">_.reduceRight(actions, _.wrap, <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123; <span class="built_in">console</span>.warn(<span class="string">'done'</span>) &#125;)(); </span><br><span class="line"><span class="comment">// the above is equivalent to what's used in Adrian's example:</span></span><br><span class="line"><span class="comment">// _(actions).reduceRight(_.wrap, function() &#123; console.warn('done') &#125;)();</span></span><br></pre></td></tr></table></figure><p>Consider the first reduction:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// _.wrap is the iteratee</span></span><br><span class="line"><span class="keyword">var</span> reduced1 = _.wrap(</span><br><span class="line">  <span class="comment">// iteratee's accumulator</span></span><br><span class="line">  <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.warn(<span class="string">'done'</span>);</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="comment">// iteratee's value</span></span><br><span class="line">  <span class="function"><span class="keyword">function</span>(<span class="params">next</span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.warn(<span class="number">4</span>);</span><br><span class="line">    next();</span><br><span class="line">  &#125;</span><br><span class="line">);</span><br><span class="line"><span class="comment">// reduced1 = function() &#123;</span></span><br><span class="line"><span class="comment">//   console.warn(4);</span></span><br><span class="line"><span class="comment">//   (function() &#123;</span></span><br><span class="line"><span class="comment">//     console.warn('done');</span></span><br><span class="line"><span class="comment">//   &#125;)();</span></span><br><span class="line"><span class="comment">// &#125;</span></span><br></pre></td></tr></table></figure><p>The second reduction:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// _.wrap is the iteratee</span></span><br><span class="line"><span class="keyword">var</span> reduced2 = _.wrap(</span><br><span class="line">  <span class="comment">// iteratee's accumulator is reduced1</span></span><br><span class="line">  <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.warn(<span class="number">4</span>);</span><br><span class="line">    (<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">      <span class="built_in">console</span>.warn(<span class="string">'done'</span>);</span><br><span class="line">    &#125;)();</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="comment">// iteratee's next value</span></span><br><span class="line">  <span class="function"><span class="keyword">function</span>(<span class="params">next</span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.warn(<span class="number">3</span>);</span><br><span class="line">    next();</span><br><span class="line">  &#125;</span><br><span class="line">);</span><br><span class="line"><span class="comment">// reduced2 = function() &#123;</span></span><br><span class="line"><span class="comment">//   console.warn(3);</span></span><br><span class="line"><span class="comment">//   (function() &#123;</span></span><br><span class="line"><span class="comment">//     console.warn(4);</span></span><br><span class="line"><span class="comment">//     (function() &#123;</span></span><br><span class="line"><span class="comment">//       console.warn('done');</span></span><br><span class="line"><span class="comment">//     &#125;)();</span></span><br><span class="line"><span class="comment">//   &#125;)();</span></span><br><span class="line"><span class="comment">// &#125;</span></span><br></pre></td></tr></table></figure><p>etc… etc… until we finally get back a function that wraps all other functions in <code>actions</code>. Hopefully, you’re starting to see how this thing sticks together.</p><h2 id="Final-example"><a href="#Final-example" class="headerlink" title="Final example"></a>Final example</h2><p>To drive the point home, let’s finish this with a less trivial, but completely useless, example:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> _ = <span class="built_in">require</span>(<span class="string">"lodash"</span>);</span><br><span class="line"><span class="keyword">var</span> inquirer = <span class="built_in">require</span>(<span class="string">"inquirer"</span>);</span><br><span class="line"><span class="keyword">var</span> fs = <span class="built_in">require</span>(<span class="string">"fs"</span>);</span><br><span class="line"><span class="keyword">var</span> path = <span class="built_in">require</span>(<span class="string">"path"</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> questions = [</span><br><span class="line">  &#123;</span><br><span class="line">    type: <span class="string">"input"</span>,</span><br><span class="line">    name: <span class="string">"username"</span>,</span><br><span class="line">    message: <span class="string">"Enter username"</span></span><br><span class="line">  &#125;,</span><br><span class="line">  &#123;</span><br><span class="line">    type: <span class="string">"password"</span>,</span><br><span class="line">    name: <span class="string">"password"</span>,</span><br><span class="line">    message: <span class="string">"Enter password"</span></span><br><span class="line">  &#125;,</span><br><span class="line">];</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> actions = [</span><br><span class="line">  <span class="function"><span class="keyword">function</span>(<span class="params">next</span>) </span>&#123;</span><br><span class="line">    inquirer.prompt(questions, <span class="function"><span class="keyword">function</span>(<span class="params">answers</span>) </span>&#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">"answers:"</span>, answers);</span><br><span class="line">      next(answers);</span><br><span class="line">    &#125;);</span><br><span class="line">  &#125;,</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">function</span>(<span class="params">next, answers</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">if</span>(answers.password === <span class="string">"sdf"</span>) &#123;</span><br><span class="line"></span><br><span class="line">      fs.readFile(path.resolve(__dirname, __filename), <span class="string">"utf-8"</span>, <span class="function"><span class="keyword">function</span>(<span class="params">err, data</span>) </span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(err) <span class="keyword">throw</span> err;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">var</span> re = <span class="keyword">new</span> <span class="built_in">RegExp</span>(answers.username);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span>(re.test(data)) &#123;</span><br><span class="line">          next(<span class="string">"there was a match"</span>);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">          next(<span class="string">"there was no match"</span>);</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;);</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">function</span>(<span class="params">next, matchRes</span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">"matchRes"</span>, matchRes);</span><br><span class="line">    next();</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">];</span><br><span class="line"></span><br><span class="line">_.reduceRight(actions, _.wrap, <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">"done"</span>);</span><br><span class="line">&#125;)();</span><br></pre></td></tr></table></figure><p>You should now have a good idea of what’s going on. Note how <code>next</code> is always bound to the next function in <code>actions</code> which needs to execute after the function in question does. Any arguments after <code>next</code> (e.g. <code>answers</code> in the second function in <code>actions</code>) are passed in when <code>next</code> is invoked in a previous function’s body (i.e. <code>next(answers)</code> in <code>actions</code>‘s first function).</p><p>You can see that we are still using callbacks when using asynchronous functions like <code>inquirer.prompt</code> and <code>fs.readFile</code>, but we avoid nesting any deeper than the inital callback passed to these asynchronous functions.</p><p>Basically, this example asks for a username and password and proceeds to read it’s own source code if password is equal to <code>&quot;sdf&quot;</code>. Also, assuming you get past the password check, an attempt to match the username against the contents of the file’s source code is carried out, and depending on the result, either <code>&quot;there was a match&quot;</code> or <code>&quot;there was no match&quot;</code> is passed to the next function in <code>actions</code>.</p><p>Since we’re never calling <code>next</code> if password does not equal <code>&quot;sdf&quot;</code>, we’re effectively breaking the chain of wrapped functions.</p><p><img src="example.png" alt="example" title="example"></p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h1 id=&quot;Intro&quot;&gt;&lt;a href=&quot;#Intro&quot; class=&quot;headerlink&quot; title=&quot;Intro&quot;&gt;&lt;/a&gt;Intro&lt;/h1&gt;&lt;p&gt;This post is based on &lt;a href=&quot;http://daemon.co.za/2012/04
      
    
    </summary>
    
      <category term="programming" scheme="http://justincalleja.com/categories/programming/"/>
    
    
      <category term="control flow" scheme="http://justincalleja.com/tags/control-flow/"/>
    
      <category term="lodash" scheme="http://justincalleja.com/tags/lodash/"/>
    
      <category term="node" scheme="http://justincalleja.com/tags/node/"/>
    
  </entry>
  
  <entry>
    <title>Marionette CompositeView an example</title>
    <link href="http://justincalleja.com/2015/02/08/marionette-compositeview-an-example/"/>
    <id>http://justincalleja.com/2015/02/08/marionette-compositeview-an-example/</id>
    <published>2015-02-08T00:00:00.000Z</published>
    <updated>2020-04-07T09:25:01.194Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Intro"><a href="#Intro" class="headerlink" title="Intro"></a>Intro</h1><p>This post is based off of an example used in the book <a href="https://shop.smashingmagazine.com/better-backbone-applications-with-marionettejs.html" title="Better Backbone Applications with MarionetteJS" target="_blank" rel="external">Better Backbone Applications with MarionetteJS</a> by <a href="http://www.joezimjs.com/" title="Joe Zimmerman" target="_blank" rel="external">Joe Zimmerman</a>. More specifically, it’s the recursive data example rendered by a combination of Collection and Composite views in Chapter 6 (itself based off of the following blog post by <a href="http://derickbailey.com/" title="Derick Bailey" target="_blank" rel="external">Derick Bailey</a>: <a href="http://lostechies.com/derickbailey/2012/04/05/composite-views-tree-structures-tables-and-more/" title="Composite Views: Tree Structures, Tables, And More" target="_blank" rel="external">Composite Views: Tree Structures, Tables, And More</a>).</p><p>I wasn’t sure I understood what was really going on in that example, so after reading the chapter, I decided to type it in and play around a bit. This post is just a description of that process (the end result <a href="https://github.com/justin-calleja/compositeview-eg" title="compositeview-eg" target="_blank" rel="external">is up on Github</a>).</p><p>I will be implementing it using AMD modules and including the few changes necessary to get it to work in <a href="http://marionettejs.com/" title="MarionetteJS" target="_blank" rel="external">Marionette</a> version 2.3.2 (the latest at time of writing). For a more detailed explanation of the example and the Marionette concepts used in it, have a look at <a href="https://shop.smashingmagazine.com/better-backbone-applications-with-marionettejs.html" title="Better Backbone Applications with MarionetteJS" target="_blank" rel="external">Better Backbone Applications with MarionetteJS</a>. I am in no way affilated with a third party and receive 0 benefit if you decide to purchase. That said, I feel confident recommending it based off of the value I’ve received from reading it.</p><h2 id="High-level-aim"><a href="#High-level-aim" class="headerlink" title="High level aim"></a>High level aim</h2><p>Basically, we want to go from:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line">[</span><br><span class="line">    &#123;</span><br><span class="line">      nodeName: <span class="string">"1"</span>,</span><br><span class="line">      nodes: [</span><br><span class="line">        &#123;</span><br><span class="line">          nodeName: <span class="string">"1.1"</span>,</span><br><span class="line">          nodes: [</span><br><span class="line">            &#123; nodeName: <span class="string">"1.1.1"</span> &#125;,</span><br><span class="line">            &#123; nodeName: <span class="string">"1.1.2"</span> &#125;,</span><br><span class="line">            &#123; nodeName: <span class="string">"1.1.3"</span> &#125;</span><br><span class="line">          ]</span><br><span class="line">        &#125;,</span><br><span class="line">        &#123;</span><br><span class="line">          nodeName: <span class="string">"1.2"</span>,</span><br><span class="line">          nodes: [</span><br><span class="line">            &#123; nodeName: <span class="string">"1.2.1"</span> &#125;,</span><br><span class="line">            &#123;</span><br><span class="line">              nodeName: <span class="string">"1.2.2"</span>,</span><br><span class="line">              nodes: [</span><br><span class="line">                &#123; nodeName: <span class="string">"1.2.2.1"</span> &#125;,</span><br><span class="line">                &#123; nodeName: <span class="string">"1.2.2.2"</span> &#125;,</span><br><span class="line">                &#123; nodeName: <span class="string">"1.2.2.3"</span> &#125;</span><br><span class="line">              ]</span><br><span class="line">            &#125;,</span><br><span class="line">            &#123; nodeName: <span class="string">"1.2.3"</span> &#125;</span><br><span class="line">          ]</span><br><span class="line">        &#125;</span><br><span class="line">      ]</span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      nodeName: <span class="string">"2"</span>,</span><br><span class="line">      nodes: [</span><br><span class="line">        &#123;</span><br><span class="line">          nodeName: <span class="string">"2.1"</span>,</span><br><span class="line">          nodes: [</span><br><span class="line">            &#123; nodeName: <span class="string">"2.1.1"</span> &#125;,</span><br><span class="line">            &#123; nodeName: <span class="string">"2.1.2"</span> &#125;,</span><br><span class="line">            &#123; nodeName: <span class="string">"2.1.3"</span> &#125;</span><br><span class="line">          ]</span><br><span class="line">        &#125;,</span><br><span class="line">        &#123;</span><br><span class="line">          nodeName: <span class="string">"2.2"</span>,</span><br><span class="line">          nodes: [</span><br><span class="line">            &#123; nodeName: <span class="string">"2.2.1"</span> &#125;,</span><br><span class="line">            &#123; nodeName: <span class="string">"2.2.2"</span> &#125;,</span><br><span class="line">            &#123; nodeName: <span class="string">"2.2.3"</span> &#125;</span><br><span class="line">          ]</span><br><span class="line">        &#125;</span><br><span class="line">      ]</span><br><span class="line">    &#125;</span><br><span class="line">  ]</span><br></pre></td></tr></table></figure><p>to:</p><div data-tree-container></div><h1 id="Setting-up"><a href="#Setting-up" class="headerlink" title="Setting up"></a>Setting up</h1><ul><li>Install Bower globally if you don’t already have it: <code>npm i -g bower</code></li><li><code>npm init</code></li><li><code>mkdir -p app/lib app/js</code></li><li><code>vim .bowerrc</code></li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="string">"directory"</span>: <span class="string">"app/lib"</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li><code>bower init</code></li><li><code>bower i --save marionette lodash requirejs</code></li></ul><figure class="highlight md"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">compositeview-eg$ ls app/lib/</span><br><span class="line">backbone            backbone.wreqr      lodash              requirejs</span><br><span class="line">backbone.babysitter jquery              marionette          underscore</span><br></pre></td></tr></table></figure><p>I am using both <a href="https://www.npmjs.com/" title="Npm" target="_blank" rel="external">Npm</a> and <a href="http://bower.io/" title="Bower" target="_blank" rel="external">Bower</a> to manage dependencies. Dependencies brought in by Npm will be used in developing the project (e.g. bringing in <a href="http://gruntjs.com/" title="Grunt" target="_blank" rel="external">Grunt</a> to automate tasks, or installing Bower so our project can use a different kind of dependency manager). Dependencies brought in by Bower will be used by the web application we’re building (i.e. these are the files consumed by the browser when it loads our application). If you’re thinking “why use 2 separate dependency managers?”, have a look at this <a href="http://stackoverflow.com/questions/18641899/difference-between-bower-and-npm" title="difference between bower and npm" target="_blank" rel="external">SO question</a>.</p><p>Basically, Npm makes use of nested dependencies which allows each dependency to have a copy of its own dependencies while Bower uses flat dependencies which means that when you bring in a dependency with Bower it will not include its own dependencies. So in the e.g. above, using Bower to bring in Marionette also gives us its dependencies, e.g. <a href="http://underscorejs.org/" title="Underscore" target="_blank" rel="external">Underscore</a> and <a href="http://backbonejs.org/" title="Backbone" target="_blank" rel="external">Backbone</a>, but these dependencies are outside of Marionette. Backbone, which also depends on Underscore, does not have its own copy of Underscore. So Underscore is shared by any dependency which needs it. This is great for pulling in dependencies which will be consumed by a browser since you do not want to load in several copies of a dependency in your application. On the server side, however, size doesn’t matter as much and using Npm allows us to cleanly use dependencies which have the correct version of their own dependencies (there are cases when this is not possible, e.g. plugins. You can read more about this at the <a href="http://blog.nodejs.org/2013/02/07/peer-dependencies/" title="NodeJS Blog" target="_blank" rel="external">NodeJS blog</a>).</p><p>Next up, we’ll configure our AMD loader and log out one of our dependencies to get some kind of indication that we’re on the right track.</p><p><code>vim app/js/main.js</code></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*global require*/</span></span><br><span class="line"><span class="pi">"use strict"</span>;</span><br><span class="line"></span><br><span class="line"><span class="built_in">require</span>.config(&#123;</span><br><span class="line">  paths: &#123;</span><br><span class="line">    jquery: <span class="string">"../lib/jquery/dist/jquery"</span>,</span><br><span class="line">    backbone: <span class="string">"../lib/backbone/backbone"</span>,</span><br><span class="line">    marionette: <span class="string">"../lib/marionette/lib/core/backbone.marionette"</span>,</span><br><span class="line">    <span class="string">"backbone.wreqr"</span>: <span class="string">"../lib/backbone.wreqr/lib/backbone.wreqr"</span>,</span><br><span class="line">    <span class="string">"backbone.babysitter"</span>: <span class="string">"../lib/backbone.babysitter/lib/backbone.babysitter"</span>,</span><br><span class="line">    underscore: <span class="string">"../lib/lodash/lodash"</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="built_in">require</span>([</span><br><span class="line">  <span class="string">"marionette"</span></span><br><span class="line">], <span class="function"><span class="keyword">function</span> (<span class="params">Marionette</span>) </span>&#123;</span><br><span class="line"></span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">"Marionette:"</span>, Marionette);</span><br><span class="line"></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>If you look inside <code>app/lib/marionette</code> you will notice that there are two Marionette scripts we could be pulling in, one in <code>marionette/lib</code> and one in <code>marionette/lib/core</code>. Both of these depend on <a href="https://github.com/marionettejs/backbone.babysitter" title="Babysitter" target="_blank" rel="external">Babysitter</a> and <a href="https://github.com/marionettejs/backbone.wreqr" title="Wreqr" target="_blank" rel="external">Wreqr</a> but the one in core pulls them in while the one outside core has these dependencies baked into its own source.</p><blockquote><p>These pre-requisites are still required for Marionette to run, but this allows you to download them separately and update them independently.</p><footer><cite><a href="http://marionettejs.com/" target="_blank" rel="external">MarionetteJS</a></cite></footer></blockquote><p>Also, if you open up <code>marionette/lib/core/backbone.marionette.js</code> you will notice that it is requiring these pre-requisites using the following aliases:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> Wreqr = <span class="built_in">require</span>(<span class="string">'backbone.wreqr'</span>);</span><br><span class="line"><span class="keyword">var</span> BabySitter = <span class="built_in">require</span>(<span class="string">'backbone.babysitter'</span>);</span><br></pre></td></tr></table></figure><p>… which is why we’re using the same alias names for the paths to these two dependencies in our AMD configuration.</p><p>The last thing we need in place to have something to serve is our index file: <code>vim app/index.html</code></p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="doctype">&lt;!DOCTYPE html&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="title">html</span> <span class="attribute">lang</span>=<span class="value">"en"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="title">head</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="title">meta</span> <span class="attribute">charset</span>=<span class="value">"UTF-8"</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="title">title</span>&gt;</span><span class="tag">&lt;/<span class="title">title</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="title">body</span>&gt;</span></span><br><span class="line">  </span><br><span class="line">  <span class="tag">&lt;<span class="title">script</span> <span class="attribute">data-main</span>=<span class="value">"js/main"</span> <span class="attribute">src</span>=<span class="value">"lib/requirejs/require.js"</span>&gt;</span><span class="undefined"></span><span class="tag">&lt;/<span class="title">script</span>&gt;</span></span><br><span class="line">  </span><br><span class="line"><span class="tag">&lt;/<span class="title">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">html</span>&gt;</span></span><br></pre></td></tr></table></figure><p>The <code>&lt;script&gt;</code> tag pulls in RequireJS from our Bower installed dependencies and configures it with the main.js file defined above. Finally, we can start some kind of server and check our progress:</p><ul><li><code>npm install -g live-server</code></li><li><code>cd app &amp;&amp; live-server</code></li></ul><p>… and you should get the console output from our main.js file.</p><h1 id="Time-to-get-cooking"><a href="#Time-to-get-cooking" class="headerlink" title="Time to get cooking"></a>Time to get cooking</h1><h2 id="The-data"><a href="#The-data" class="headerlink" title="The data"></a>The data</h2><p>We’ll start off by defining how our data will be stored as Models and Collections:</p><p><code>vim app/js/tree/TreeNode.js</code></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*global define*/</span></span><br><span class="line"></span><br><span class="line">define([</span><br><span class="line">  <span class="string">"backbone"</span></span><br><span class="line">], <span class="function"><span class="keyword">function</span> (<span class="params">Backbone</span>) </span>&#123;</span><br><span class="line"><span class="pi">  "use strict"</span>;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">var</span> NodeModel = Backbone.Model.extend(&#123;</span><br><span class="line"></span><br><span class="line">    initialize: <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">      <span class="keyword">var</span> nodes = <span class="keyword">this</span>.get(<span class="string">"nodes"</span>);</span><br><span class="line">      <span class="comment">// Covert nodes to a NodeCollection</span></span><br><span class="line">      <span class="keyword">this</span>.set(<span class="string">"nodes"</span>, <span class="keyword">new</span> NodeCollection(nodes));</span><br><span class="line">    &#125;,</span><br><span class="line"></span><br><span class="line">    toJSON: <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">      <span class="comment">// Call parent's toJSON method</span></span><br><span class="line">      <span class="keyword">var</span> data = Backbone.Model.prototype.toJSON.call(<span class="keyword">this</span>);</span><br><span class="line">      <span class="keyword">if</span> (data.nodes &amp;&amp; data.nodes.toJSON) &#123;</span><br><span class="line">        <span class="comment">// If nodes is a collection, convert it to JSON</span></span><br><span class="line">        data.nodes = data.nodes.toJSON();</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">return</span> data;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">  &#125;);</span><br><span class="line"></span><br><span class="line">  <span class="keyword">var</span> NodeCollection = Backbone.Collection.extend(&#123;</span><br><span class="line">    model: NodeModel</span><br><span class="line">  &#125;);</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> &#123;</span><br><span class="line">    Model: NodeModel,</span><br><span class="line">    Collection: NodeCollection</span><br><span class="line">  &#125;;</span><br><span class="line"></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>Notice how we define both the Model and the Collection in the same module since they are interdependent. We could not separate these into their own separate module as each definition would depend on the other being loaded and this would inevitably lead to undefined imports when running it in our browser.</p><p>Also notice that upon initialization, NodeModel will look for a <em>nodes</em> attribute and encapsulate it in a new <em>NodeCollection</em>. A NodeCollection is itself a collection of NodeModels and so the process will repeat as long a given NodeModel contains any nodes. A similar process takes place when deserializing the Model’s state in <em>toJSON</em>.</p><p>With that in place, leave live-server running and change <em>main.js</em> to use TreeNode:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">require</span>([</span><br><span class="line">  <span class="string">"tree/TreeNode"</span></span><br><span class="line">], <span class="function"><span class="keyword">function</span> (<span class="params">TreeNode</span>) </span>&#123;</span><br><span class="line"></span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">"TreeNode.Model:"</span>, TreeNode.Model);</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">"TreeNode.Collection:"</span>, TreeNode.Collection);</span><br><span class="line"></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>Again, you should see the relevant changes in the console.</p><p>We’ll now add the data from which we will be creating our models and collections:</p><p><code>vim app/js/tree/nodeData.js</code></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*global define*/</span></span><br><span class="line"></span><br><span class="line">define(<span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line"><span class="pi">  "use strict"</span>;</span><br><span class="line"> </span><br><span class="line">  <span class="keyword">return</span> [</span><br><span class="line">    &#123;</span><br><span class="line">      nodeName: <span class="string">"1"</span>,</span><br><span class="line">      nodes: [</span><br><span class="line">        &#123;</span><br><span class="line">          nodeName: <span class="string">"1.1"</span>,</span><br><span class="line">          nodes: [</span><br><span class="line">            &#123; nodeName: <span class="string">"1.1.1"</span> &#125;,</span><br><span class="line">            &#123; nodeName: <span class="string">"1.1.2"</span> &#125;,</span><br><span class="line">            &#123; nodeName: <span class="string">"1.1.3"</span> &#125;</span><br><span class="line">          ]</span><br><span class="line">        &#125;,</span><br><span class="line">        &#123;</span><br><span class="line">          nodeName: <span class="string">"1.2"</span>,</span><br><span class="line">          nodes: [</span><br><span class="line">            &#123; nodeName: <span class="string">"1.2.1"</span> &#125;,</span><br><span class="line">            &#123;</span><br><span class="line">              nodeName: <span class="string">"1.2.2"</span>,</span><br><span class="line">              nodes: [</span><br><span class="line">                &#123; nodeName: <span class="string">"1.2.2.1"</span> &#125;,</span><br><span class="line">                &#123; nodeName: <span class="string">"1.2.2.2"</span> &#125;,</span><br><span class="line">                &#123; nodeName: <span class="string">"1.2.2.3"</span> &#125;</span><br><span class="line">              ]</span><br><span class="line">            &#125;,</span><br><span class="line">            &#123; nodeName: <span class="string">"1.2.3"</span> &#125;</span><br><span class="line">          ]</span><br><span class="line">        &#125;</span><br><span class="line">      ]</span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      nodeName: <span class="string">"2"</span>,</span><br><span class="line">      nodes: [</span><br><span class="line">        &#123;</span><br><span class="line">          nodeName: <span class="string">"2.1"</span>,</span><br><span class="line">          nodes: [</span><br><span class="line">            &#123; nodeName: <span class="string">"2.1.1"</span> &#125;,</span><br><span class="line">            &#123; nodeName: <span class="string">"2.1.2"</span> &#125;,</span><br><span class="line">            &#123; nodeName: <span class="string">"2.1.3"</span> &#125;</span><br><span class="line">          ]</span><br><span class="line">        &#125;,</span><br><span class="line">        &#123;</span><br><span class="line">          nodeName: <span class="string">"2.2"</span>,</span><br><span class="line">          nodes: [</span><br><span class="line">            &#123; nodeName: <span class="string">"2.2.1"</span> &#125;,</span><br><span class="line">            &#123; nodeName: <span class="string">"2.2.2"</span> &#125;,</span><br><span class="line">            &#123; nodeName: <span class="string">"2.2.3"</span> &#125;</span><br><span class="line">          ]</span><br><span class="line">        &#125;</span><br><span class="line">      ]</span><br><span class="line">    &#125;</span><br><span class="line">  ];</span><br><span class="line"></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>At this stage, if you want to experiment a bit with what we have, you could create a TreeNode.Collection in main.js like so:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">require</span>([</span><br><span class="line">  <span class="string">"tree/TreeNode"</span>,</span><br><span class="line">  <span class="string">"tree/nodeData"</span></span><br><span class="line">], <span class="function"><span class="keyword">function</span> (<span class="params">TreeNode, nodeData</span>) </span>&#123;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">var</span> nodes = <span class="keyword">new</span> TreeNode.Collection(nodeData);</span><br><span class="line">  <span class="built_in">window</span>.nodes = nodes;</span><br><span class="line">  <span class="built_in">console</span>.log(nodes);</span><br><span class="line"></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h2 id="The-views"><a href="#The-views" class="headerlink" title="The views"></a>The views</h2><p>We’ll now turn our attention to rendering our data in the browser. For this we’ll be using both Marionette’s <a href="http://marionettejs.com/docs/v2.3.2/marionette.compositeview.html" target="_blank" rel="external">CompositeView</a> and <a href="http://marionettejs.com/docs/v2.3.2/marionette.collectionview.html" target="_blank" rel="external">CollectionView</a> capabilities.</p><p>Take another look at the data structure shown at the beginning of <a href="#toc_1">High level aim</a>. You will notice that we’re working with an array with two objects inside it. Each object in the array may contain a <em>nodes</em> array which itself is made up of objects which may or may not contain a <em>nodes</em> array. We can consider each of these objects as nodes in a tree, with the node at the top level array as the root and any nodes with no children as leaves.</p><p>This is probably easier to illustrate with a diagram than to describe in words:</p><p><img id="views-diagram" src="/marionette-compositeview-an-example/svg/views.svg" onerror="this.onerror=null; this.src='/marionette-compositeview-an-example/img/views.png'"></p><p>This diagram also shows where the Marionette Views come into play. Note that there is only one collection shown in this diagram which is backed by a CollectionView - the top level collection containing the root CompositeView nodes. The <em>nodes</em> collection within each CompositeView is not backed by a CollectionView. They are just the CompositeView’s collection.</p><p>A CompositeView is made up of both a model <em>and</em> a collection. It has it’s own template, which is the “wrapper template” mentioned in this piece of documentation:</p><blockquote><p>A CompositeView extends from CollectionView to be used as a composite view for scenarios where it should represent both a branch and leaf in a tree structure, or for scenarios where a collection needs to be rendered within a wrapper template.</p><footer><cite><a href="http://marionettejs.com/docs/v2.3.2/marionette.compositeview.html" target="_blank" rel="external">MarionetteJS Docs</a></cite></footer></blockquote><p>Additionally, if you don’t specify what kind of view each element in a CompositeView’s collection is, it will be assumed to be the same as the CompositeView in question:</p><blockquote><p>The default rendering mode for a CompositeView assumes a hierarchical, recursive structure. If you configure a composite view without specifying a childView, you’ll get the same composite view class rendered for each child in the collection.</p><footer><cite><a href="http://marionettejs.com/docs/v2.3.2/marionette.compositeview.html#recursive-by-default" target="_blank" rel="external">MarionetteJS Docs</a></cite></footer></blockquote><p>This will make more sense when we take a look at the code below, but for now, keep in mind that a CollectionView renders our top level root nodes. The tree stemming from each root node is recursively rendered and the view used behind the scenes to do this is a CompositeView. </p><h3 id="CompositeView"><a href="#CompositeView" class="headerlink" title="CompositeView"></a>CompositeView</h3><p><code>vim app/js/tree/TreeCompositeView.js</code></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*global define*/</span></span><br><span class="line"></span><br><span class="line">define([</span><br><span class="line">  <span class="string">"marionette"</span>,</span><br><span class="line">  <span class="string">"ejsTemplates"</span></span><br><span class="line">], <span class="function"><span class="keyword">function</span> (<span class="params">Marionette, JST</span>) </span>&#123;</span><br><span class="line"><span class="pi">  "use strict"</span>;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">var</span> CompositeView = Marionette.CompositeView.extend(&#123;</span><br><span class="line"></span><br><span class="line">    template: JST[<span class="string">"app/ejs/tree/treeViewComposite.ejs"</span>],</span><br><span class="line"></span><br><span class="line">    tagName: <span class="string">"li"</span>,</span><br><span class="line"></span><br><span class="line">    <span class="comment">// specifies a selector for the element we want the</span></span><br><span class="line">    <span class="comment">// child elements placed into</span></span><br><span class="line">    childViewContainer: <span class="string">"ul"</span>,</span><br><span class="line"></span><br><span class="line">    initialize: <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">      <span class="comment">// grab the child collection from the parent model</span></span><br><span class="line">      <span class="comment">// so that we can render the collection as children</span></span><br><span class="line">      <span class="comment">// of this parent node</span></span><br><span class="line">      <span class="keyword">this</span>.collection = <span class="keyword">this</span>.model.get(<span class="string">"nodes"</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">  &#125;);</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> CompositeView;</span><br><span class="line"></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>With this definition, our TreeCompositeView’s model will be rendered using the specified template (more on this shortly) and placed in an <code>&lt;li&gt;</code> tag.</p><p>Each element in our TreeCompositeView’s collection will also be rendered using TreeCompositeView’s template because, since we haven’t specified a childView, each element in TreeCompositeView’s collection is considered to be a TreeCompositeView.</p><p>In addition, each TreeCompositeView in a given TreeCompositeView’s collection, once rendered, will be placed in a <code>&lt;ul&gt;</code> tag which the given TreeCompositeView is expected to render (that’s what the <code>childViewContainer</code> attribute is there for).</p><p>Regarding the <code>&quot;ejsTemplates&quot;</code> import, you can have a look at a <a href="../grunt-watch-those-templates">previous post</a> on this blog which explains how you can get a compiled Javascript template from an EJS file like the following:</p><p><code>vim app/ejs/tree/treeViewComposite.ejs</code></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">&lt;% <span class="keyword">if</span>(nodes.length &gt; <span class="number">0</span>) &#123; %&gt;</span><br><span class="line">    <span class="xml"><span class="tag">&lt;<span class="title">%=</span> <span class="attribute">nodeName</span> %&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">ul</span>&gt;</span><span class="tag">&lt;/<span class="title">ul</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="title">%</span> &#125; <span class="attribute">else</span> &#123; %&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">%=</span> <span class="attribute">nodeName</span> %&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="title">%</span> &#125; %&gt;</span></span></span><br></pre></td></tr></table></figure><p><em>The Gruntfile used in this step is up on <a href="https://github.com/justin-calleja/compositeview-eg" title="compositeview-eg" target="_blank" rel="external">Github</a></em></p><p>After the compilation takes place (e.g using a Grunt watch task as described in the post linked to above), you will need to alias the path to <code>&quot;ejsTemplates&quot;</code> in your RequireJS main config file. Assuming, we’re compiling to <code>app/js/templates/ejsTemplates.js</code>, and since our main.js file is in <code>app/js</code>, the addition to our main.js file’s paths would be:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ejsTemplates: <span class="string">"./templates/ejsTemplates"</span></span><br></pre></td></tr></table></figure><p>The EJS file itself is quite straightforward. We simply render the nodeName or a combination of the nodeName and an empty <code>&lt;ul&gt;</code> element depending on whether or not we have any nodes in the CompositeView’s model. This conditional logic will allow us to avoid having an empty <code>&lt;ul&gt;</code> element when rendering our leaf CompositeView nodes.</p><p>It might be worth repeating that whatever gets rendered here is wrapped up in an <code>&lt;li&gt;</code> element, as per our CompositeView’s <code>tagName</code> attribute.</p><h3 id="CollectionView"><a href="#CollectionView" class="headerlink" title="CollectionView"></a>CollectionView</h3><p><code>vim app/js/tree/TreeCollectionView.js</code></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*global define*/</span></span><br><span class="line"></span><br><span class="line">define([</span><br><span class="line">  <span class="string">"marionette"</span>,</span><br><span class="line">  <span class="string">"ejsTemplates"</span>,</span><br><span class="line">  <span class="string">"tree/TreeCompositeView"</span></span><br><span class="line">], <span class="function"><span class="keyword">function</span> (<span class="params">Marionette, JST, TreeCompositeView</span>) </span>&#123;</span><br><span class="line"><span class="pi">  "use strict"</span>;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">var</span> TreeCollectionView = Marionette.CollectionView.extend(&#123;</span><br><span class="line">      tagName: <span class="string">"ul"</span>,</span><br><span class="line">      childView: TreeCompositeView</span><br><span class="line">  &#125;);</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> TreeCollectionView;</span><br><span class="line"></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>The first line in the online doc pretty much sums it up:</p><blockquote><p>The <code>CollectionView</code> will loop through all of the models in the specified collection, render each of them using a specified <code>childView</code>, then append the results of the child view’s <code>el</code> to the collection view’s <code>el</code>.</p><footer><cite><a href="http://marionettejs.com/docs/v2.3.2/marionette.collectionview.html" target="_blank" rel="external">MarionetteJS Docs</a></cite></footer></blockquote><p>In our case, this translates to something along the lines of:</p><blockquote><p>The TreeCollectionView will loop through all of the models in its collection, render each of them as TreeCompositeViews (and hence get the <code>&lt;li&gt;...&lt;ul&gt;...&lt;/ul&gt;...&lt;/li&gt;</code> nested effect), then append the results of the root TreeCompositeViews <code>el</code> to the TreeCollectionView’s <code>el</code> which is a <code>&lt;ul&gt;</code> element.</p></blockquote><h2 id="Using-what-we’ve-got"><a href="#Using-what-we’ve-got" class="headerlink" title="Using what we’ve got"></a>Using what we’ve got</h2><p>We’re finally ready to pull things together in main.js:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*global require*/</span></span><br><span class="line"><span class="pi">"use strict"</span>;</span><br><span class="line"></span><br><span class="line"><span class="built_in">require</span>.config(&#123;</span><br><span class="line">  paths: &#123;</span><br><span class="line">    jquery: <span class="string">"../lib/jquery/dist/jquery"</span>,</span><br><span class="line">    backbone: <span class="string">"../lib/backbone/backbone"</span>,</span><br><span class="line">    marionette: <span class="string">"../lib/marionette/lib/core/backbone.marionette"</span>,</span><br><span class="line">    <span class="string">"backbone.wreqr"</span>: <span class="string">"../lib/backbone.wreqr/lib/backbone.wreqr"</span>,</span><br><span class="line">    <span class="string">"backbone.babysitter"</span>: <span class="string">"../lib/backbone.babysitter/lib/backbone.babysitter"</span>,</span><br><span class="line">    underscore: <span class="string">"../lib/lodash/lodash"</span>,</span><br><span class="line">    ejsTemplates: <span class="string">"./templates/ejsTemplates"</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="built_in">require</span>([</span><br><span class="line">  <span class="string">"tree/TreeNode"</span>,</span><br><span class="line">  <span class="string">"tree/nodeData"</span>,</span><br><span class="line">  <span class="string">"tree/TreeCollectionView"</span></span><br><span class="line">], <span class="function"><span class="keyword">function</span> (<span class="params">TreeNode, nodeData, TreeCollectionView</span>) </span>&#123;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">var</span> nodes = <span class="keyword">new</span> TreeNode.Collection(nodeData);</span><br><span class="line">  <span class="keyword">var</span> tree = <span class="keyword">new</span> TreeCollectionView(&#123;</span><br><span class="line">    collection: nodes</span><br><span class="line">  &#125;);</span><br><span class="line">  tree.render();</span><br><span class="line">  $(<span class="string">"[data-tree-container]"</span>).append(tree.el);</span><br><span class="line"></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>Notice that our trees will only grow in elements with the <code>data-tree-container</code> attribute so you’ll want to add something like this to your index.html:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="title">div</span> <span class="attribute">data-tree-container</span> /&gt;</span></span><br></pre></td></tr></table></figure><h1 id="Wrapping-up"><a href="#Wrapping-up" class="headerlink" title="Wrapping up"></a>Wrapping up</h1><p>I’m including this section mainly because the pieces it describes are included in the <a href="https://github.com/justin-calleja/compositeview-eg" title="compositeview-eg" target="_blank" rel="external">Github repo</a> for this post (i.e. for completeness sake).</p><ul><li><code>npm i --save-dev grunt-contrib-requirejs</code></li><li><code>bower i --save almond</code></li></ul><p>We’ll be using <a href="https://github.com/gruntjs/grunt-contrib-requirejs" title="grunt-contrib-requirejs" target="_blank" rel="external">grunt-contrib-requirejs</a> to concatenate and uglify our scripts and <a href="https://github.com/jrburke/almond" title="Almond" target="_blank" rel="external">Almond</a> to do our module loading. In <a href="https://github.com/jrburke" title="jrburke" target="_blank" rel="external">James</a>‘s own words, Almond is:</p><blockquote><p>A replacement AMD loader for RequireJS. It provides a minimal AMD API footprint that includes loader plugin support. Only useful for built/bundled AMD modules, does not do dynamic loading.</p><footer><cite><a href="https://github.com/jrburke/almond#almond" target="_blank" rel="external">Almond</a></cite></footer></blockquote><p>Simply include the following configuration in your Gruntfile.js:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// ...</span></span><br><span class="line"></span><br><span class="line">requirejs: &#123;</span><br><span class="line">  compile: &#123;</span><br><span class="line">    options: &#123;</span><br><span class="line">      baseUrl: <span class="string">"app/js"</span>,</span><br><span class="line">      mainConfigFile: <span class="string">"app/js/main.js"</span>,</span><br><span class="line">      preserveLicenseComments: <span class="literal">false</span>,</span><br><span class="line">      useStrict: <span class="literal">true</span>,</span><br><span class="line">      include: [<span class="string">"../lib/almond/almond"</span>, <span class="string">"main"</span>],</span><br><span class="line">      out: <span class="string">"dist/main.min.js"</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// ...</span></span><br><span class="line"></span><br><span class="line">grunt.registerTask(<span class="string">"build"</span>, [<span class="string">"jst:compile"</span>, <span class="string">"requirejs:compile"</span>]);</span><br></pre></td></tr></table></figure><p>We’re using our <code>app/js/main.js</code> file as part of the build configuration and we’re including the Almond fetched by bower in our built artifact - <code>dist/main.min.js</code>.</p><p>You’re now ready to build with <code>grunt build</code> and include the generated script in your own files. It is being used in the page you’re viewing:</p><div data-tree-container></div><style>img#views-diagram {    width: 85%;}</style><script src="/marionette-compositeview-an-example/js/main.min.js"></script>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h1 id=&quot;Intro&quot;&gt;&lt;a href=&quot;#Intro&quot; class=&quot;headerlink&quot; title=&quot;Intro&quot;&gt;&lt;/a&gt;Intro&lt;/h1&gt;&lt;p&gt;This post is based off of an example used in the book &lt;a h
      
    
    </summary>
    
      <category term="programming" scheme="http://justincalleja.com/categories/programming/"/>
    
    
      <category term="marionette.js" scheme="http://justincalleja.com/tags/marionette-js/"/>
    
      <category term="requirejs" scheme="http://justincalleja.com/tags/requirejs/"/>
    
  </entry>
  
  <entry>
    <title>Grunt watch those templates</title>
    <link href="http://justincalleja.com/2015/01/18/grunt-watch-those-templates/"/>
    <id>http://justincalleja.com/2015/01/18/grunt-watch-those-templates/</id>
    <published>2015-01-18T00:00:00.000Z</published>
    <updated>2020-04-07T09:25:01.192Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Purpose"><a href="#Purpose" class="headerlink" title="Purpose"></a>Purpose</h1><p>Setting up automatic <a href="http://www.embeddedjs.com/" title="Embedded JS" target="_blank" rel="external">EJS</a> (Underscore/Lo-Dash) and <a href="http://handlebarsjs.com/" title="Handlebars" target="_blank" rel="external">Handlebars</a> template compilation in <a href="http://gruntjs.com/" title="Grunt" target="_blank" rel="external">Grunt</a> using <a href="https://github.com/gruntjs/grunt-contrib-watch" title="grunt-contrib-watch" target="_blank" rel="external">grunt-contrib-watch</a>.</p><p>The aim is to be able to spawn a process which will watch our templates and compile them to JST (Javascript template) files while we’re editing them. That way we can write our templates in a more readable fashion but use the actual JST files at runtime (thus avoiding the need to compile them dynamically).</p><h1 id="Starting-to-watch"><a href="#Starting-to-watch" class="headerlink" title="Starting to watch"></a>Starting to watch</h1><p><code>cd</code> into an empty directory and:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">$ npm init</span><br><span class="line">$ npm i --save-dev grunt grunt-contrib-jst grunt-contrib-watch load-grunt-tasks grunt-contrib-handlebars</span><br><span class="line">$ mkdir -p app/scripts</span><br></pre></td></tr></table></figure><p>Start the Gruntfile.js configuration with the following, just to check that watch is working:</p><p><code>vim Gruntfile.js</code></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="pi">'use strict'</span>;</span><br><span class="line"></span><br><span class="line"><span class="built_in">module</span>.exports = <span class="function"><span class="keyword">function</span> (<span class="params">grunt</span>) </span>&#123;</span><br><span class="line"></span><br><span class="line">  <span class="built_in">require</span>(<span class="string">'load-grunt-tasks'</span>)(grunt);</span><br><span class="line"></span><br><span class="line">  grunt.initConfig(&#123;</span><br><span class="line">    watch: &#123;</span><br><span class="line">      options: &#123;</span><br><span class="line">        nospawn: <span class="literal">true</span></span><br><span class="line">      &#125;,</span><br><span class="line">      log: &#123;</span><br><span class="line">        files: [</span><br><span class="line">          <span class="string">'app/scripts/**/*.js'</span></span><br><span class="line">        ],</span><br><span class="line">        tasks: [<span class="string">'tmpLog'</span>]</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;);</span><br><span class="line"></span><br><span class="line">  grunt.registerTask(<span class="string">'tmpLog'</span>, <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">    grunt.log.write(<span class="string">'watchin is workin'</span>);</span><br><span class="line">  &#125;);</span><br><span class="line"></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>Running <code>grunt watch</code> and editing a JS file in <em>‘app/scripts/**/*.js’</em> (e.g. <em>app/scripts/tmp.js</em>) should give the following output:</p><img src="/2015/01/18/grunt-watch-those-templates/watch-is-working.png" alt="[Screenshot showing that watch is set up]" title="[Screenshot showing that watch is set up]"><h1 id="Compiling-EJS-templates"><a href="#Compiling-EJS-templates" class="headerlink" title="Compiling EJS templates"></a>Compiling EJS templates</h1><p>Replace watch’s <code>log</code> option with the following:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">jst: &#123;</span><br><span class="line">  files: [</span><br><span class="line">    <span class="string">'app/scripts/templates/ejs/**/*.ejs'</span></span><br><span class="line">  ],</span><br><span class="line">  tasks: [<span class="string">'jst:compile'</span>]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Configure JST compilation for EJS files with the following (don’t include <em>amd: true</em> if you’re not working with an AMD module loader like RequireJS):</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">jst: &#123;</span><br><span class="line">  options: &#123;</span><br><span class="line">    amd: <span class="literal">true</span></span><br><span class="line">  &#125;,</span><br><span class="line">  compile: &#123;</span><br><span class="line">    files: &#123;</span><br><span class="line">      <span class="string">'app/scripts/templates/jst/ejsTemplates.js'</span>: [<span class="string">'app/scripts/templates/ejs/**/*.ejs'</span>]</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Personally, I find using <code>jst</code> for the key a bit confusing. The way I understand it is that both <em>grunt-contrib-jst</em> and <em>grunt-contrib-handlebars</em>, as well as any other JST compiler, compiles some kind of template file to a Javascript file in order to make the authoring and maintaing of these JST files easier (since these Javascript files tend to be heavy on string concatenation and such).</p><p>Since <em>grunt-contrib-jst</em> compiles <a href="http://www.embeddedjs.com/" title="Embedded JS" target="_blank" rel="external">EJS</a> templates, it seems to me that it would have made more sense to call the plugin <em>grunt-contrib-ejs</em> and to use <em>ejs</em> as the key to configure this plugin in <em>grunt.initConfig</em>. But the key to use for the plugin is <code>jst</code>, so I’m also sticking to <code>jst</code> in the <em>watch</em> plugin configuration. I will, however, be suffixing these template files with <em>.ejs</em>, hence the above configuration.</p><p>Running <code>grunt watch</code> and editing an EJS file in our watched path should trigger the compilation, e.g:</p><p><code>vim app/scripts/templates/ejs/tmp.ejs</code></p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&#60;ul&#62;&#10;    &#60;% for(var i=0; i&#60;supplies.length; i++) &#123; %&#62;&#10;        &#60;li&#62;&#10;            &#60;a href=&#39;supplies/&#60;%= supplies[i] %&#62;&#39;&#62;&#10;                &#60;%= supplies[i] %&#62;&#10;            &#60;/a&#62;&#10;        &#60;/li&#62;&#10;    &#60;% &#125; %&#62;&#10;&#60;/ul&#62;</span><br></pre></td></tr></table></figure><h1 id="Compiling-Handlebars-templates"><a href="#Compiling-Handlebars-templates" class="headerlink" title="Compiling Handlebars templates"></a>Compiling Handlebars templates</h1><p>Add the following option to the <em>watch</em> task configuration:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">handlebars: &#123;</span><br><span class="line">  files: [</span><br><span class="line">    <span class="string">'app/scripts/templates/hbs/**/*.hbs'</span></span><br><span class="line">  ],</span><br><span class="line">  tasks: [<span class="string">'handlebars:compile'</span>]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Then configure the <em>grunt-contrib-handlebars</em> plugin itself (again, I want the generated JST file to be wrapped in an AMD define, YMMV):</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">handlebars: &#123;</span><br><span class="line">  options: &#123;</span><br><span class="line">    amd: <span class="literal">true</span></span><br><span class="line">  &#125;,</span><br><span class="line">  compile: &#123;</span><br><span class="line">    files: &#123;</span><br><span class="line">      <span class="string">'app/scripts/templates/jst/hbsTemplates.js'</span>: [<span class="string">'app/scripts/templates/hbs/**/*.hbs'</span>]</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Try it out:</p><p><code>vim app/scripts/templates/hbs/tmp.hbs</code></p><figure class="highlight handlebars"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="xml"><span class="tag">&lt;<span class="title">div</span> <span class="attribute">class</span>=<span class="value">"entry"</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="title">h1</span>&gt;</span></span><span class="expression">&#123;&#123;<span class="variable">title</span>&#125;&#125;</span><span class="xml"><span class="tag">&lt;/<span class="title">h1</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="title">div</span> <span class="attribute">class</span>=<span class="value">"body"</span>&gt;</span></span><br><span class="line">    </span><span class="expression">&#123;&#123;<span class="variable">body</span>&#125;&#125;</span><span class="xml"></span><br><span class="line">  <span class="tag">&lt;/<span class="title">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">div</span>&gt;</span></span></span><br></pre></td></tr></table></figure><p>… and assuming you’ve restarted <code>grunt watch</code> and it’s running in the background, you should get <em>hbsTemplates.js</em>.</p><h1 id="Final-Gruntfile-js"><a href="#Final-Gruntfile-js" class="headerlink" title="Final Gruntfile.js"></a>Final Gruntfile.js</h1><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"><span class="pi">'use strict'</span>;</span><br><span class="line"></span><br><span class="line"><span class="built_in">module</span>.exports = <span class="function"><span class="keyword">function</span> (<span class="params">grunt</span>) </span>&#123;</span><br><span class="line"></span><br><span class="line">  <span class="built_in">require</span>(<span class="string">'load-grunt-tasks'</span>)(grunt);</span><br><span class="line"></span><br><span class="line">  grunt.initConfig(&#123;</span><br><span class="line"></span><br><span class="line">    watch: &#123;</span><br><span class="line">      options: &#123;</span><br><span class="line">        nospawn: <span class="literal">true</span></span><br><span class="line">      &#125;,</span><br><span class="line">      jst: &#123;</span><br><span class="line">        files: [</span><br><span class="line">          <span class="string">'app/scripts/templates/ejs/**/*.ejs'</span></span><br><span class="line">        ],</span><br><span class="line">        tasks: [<span class="string">'jst:compile'</span>]</span><br><span class="line">      &#125;,</span><br><span class="line">      handlebars: &#123;</span><br><span class="line">        files: [</span><br><span class="line">          <span class="string">'app/scripts/templates/hbs/**/*.hbs'</span></span><br><span class="line">        ],</span><br><span class="line">        tasks: [<span class="string">'handlebars:compile'</span>]</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;,</span><br><span class="line"></span><br><span class="line">    jst: &#123;</span><br><span class="line">      options: &#123;</span><br><span class="line">        amd: <span class="literal">true</span></span><br><span class="line">      &#125;,</span><br><span class="line">      compile: &#123;</span><br><span class="line">        files: &#123;</span><br><span class="line">          <span class="string">'app/scripts/templates/jst/ejsTemplates.js'</span>: [<span class="string">'app/scripts/templates/ejs/**/*.ejs'</span>]</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;,</span><br><span class="line"></span><br><span class="line">    handlebars: &#123;</span><br><span class="line">      options: &#123;</span><br><span class="line">        amd: <span class="literal">true</span></span><br><span class="line">      &#125;,</span><br><span class="line">      compile: &#123;</span><br><span class="line">        files: &#123;</span><br><span class="line">          <span class="string">'app/scripts/templates/jst/hbsTemplates.js'</span>: [<span class="string">'app/scripts/templates/hbs/**/*.hbs'</span>]</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">  &#125;);</span><br><span class="line"></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h1 id=&quot;Purpose&quot;&gt;&lt;a href=&quot;#Purpose&quot; class=&quot;headerlink&quot; title=&quot;Purpose&quot;&gt;&lt;/a&gt;Purpose&lt;/h1&gt;&lt;p&gt;Setting up automatic &lt;a href=&quot;http://www.embeddedj
      
    
    </summary>
    
      <category term="programming" scheme="http://justincalleja.com/categories/programming/"/>
    
    
      <category term="grunt" scheme="http://justincalleja.com/tags/grunt/"/>
    
  </entry>
  
  <entry>
    <title>Getting started with Assemble</title>
    <link href="http://justincalleja.com/2015/01/10/getting-started-with-assemble/"/>
    <id>http://justincalleja.com/2015/01/10/getting-started-with-assemble/</id>
    <published>2015-01-10T00:00:00.000Z</published>
    <updated>2020-04-07T09:25:01.192Z</updated>
    
    <content type="html"><![CDATA[<p>Version of Assemble at time of writing: 0.4.42</p><p>If you want to follow along with the end result at hand, the repo is up on <a href="https://github.com/justin-calleja/getting-started-with-assemble" title="getting-started-with-assemble" target="_blank" rel="external">Github</a>.</p><h1 id="Intro"><a href="#Intro" class="headerlink" title="Intro"></a>Intro</h1><p><a href="https://github.com/assemble/assemble" title="Assemble" target="_blank" rel="external">Assemble</a>, in their own words, is a static site generator for Grunt.js, Yeoman and Node.js. This blog post is a record of the approach taken and material covered during my first time usage of Assemble.</p><h2 id="grunt-init-assemble"><a href="#grunt-init-assemble" class="headerlink" title="grunt-init-assemble"></a>grunt-init-assemble</h2><p>The first approach I took was to have a go at the <a href="https://github.com/gruntjs/grunt-init" title="grunt-init" target="_blank" rel="external">grunt-init</a> template for Assemble, <a href="https://github.com/ghost-town/grunt-init-assemble" title="grunt-init-assemble" target="_blank" rel="external">grunt-init-assemble</a>:</p><ol><li><code>npm i -g grunt-cli grunt-init</code> if you don’t already have them installed.</li><li><code>git clone https://github.com/ghost-town/grunt-init-assemble ~/.grunt-init/assemble</code><ul><li>Allows us to scaffold a new Assemble project using grunt-init.</li></ul></li><li>cd into an empty directory and <code>grunt-init assemble</code><ul><li>This will look in ~/.grunt-init by default.</li></ul></li><li><code>npm install &amp;&amp; bower install</code> to bring in Node and Bower packages.</li><li><code>grunt setup</code> runs a task which is defined in the generated Gruntfile.js.</li><li>Go though your Gruntfile.js and delete the sections marked for deletion in the comments (they were there just for running <code>grunt setup</code> and should be removed after executing this task).</li></ol><p>This leaves us with a bootstrapped Assemble project. If you’re not familiar with Assemble, it’s a good idea to have a look at the generated project. The rest of this post builds an example project from scratch i.e. without starting off using <em>grunt-init-assemble</em>, however, I am using the generated project as a guide - “cherry picking” if you will.</p><h1 id="Starting-from-scratch"><a href="#Starting-from-scratch" class="headerlink" title="Starting from scratch"></a>Starting from scratch</h1><p>The idea is to run Assemble as part of a <a href="http://gruntjs.com/" title="Grunt" target="_blank" rel="external">Grunt</a> build and end up with a page assembled from bits and pieces with the help of Assemble. Along the way, we’ll be taking a look at what goes in to working with an Assemble project.</p><h2 id="config-yml-and-Gruntfile-js"><a href="#config-yml-and-Gruntfile-js" class="headerlink" title="_config.yml and Gruntfile.js"></a>_config.yml and Gruntfile.js</h2><ol><li><code>npm init &amp;&amp; npm i --save-dev grunt grunt-contrib-clean assemble</code></li><li><code>vim _config.yml</code><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">root:             public</span><br><span class="line">dest:             &lt;%= site.root %&gt;</span><br><span class="line">assets:           &lt;%= site.dest %&gt;/assets</span><br><span class="line"></span><br><span class="line">data:             data/*.&#123;json,yml&#125;</span><br><span class="line"></span><br><span class="line">templates:        templates</span><br><span class="line">includes:         &lt;%= site.templates %&gt;/includes/*.hbs</span><br><span class="line">layouts:          &lt;%= site.templates %&gt;/layouts</span><br><span class="line">layout:           default.hbs</span><br><span class="line"></span><br><span class="line">helpers:          </span><br><span class="line">  - &lt;%= site.templates %&gt;/helpers/*.js</span><br><span class="line"></span><br><span class="line">description:      &lt;%= pkg.description %&gt;</span><br></pre></td></tr></table></figure></li></ol><p>Apart from pulling in some dependencies we’re setting up a _config.yml from which we’ll be accessing values to set up our Assemble configuration in the Gruntfile. Speaking of which, lets get a minimal Gruntfile in place. From the snippet below, notice how the <em>site</em> variable references the object built from parsing _config.yml. So when used in _config.yml above, you can think of <em>site</em> as being sort of like <em>this</em>, a reference to itself - again I am basing my approach off of the grunt-init-assemble example above.</p><p><code>vim Gruntfile.js</code><br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">module</span>.exports = <span class="function"><span class="keyword">function</span>(<span class="params">grunt</span>) </span>&#123;</span><br><span class="line"><span class="pi">'use strict'</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// Project configuration.</span></span><br><span class="line">  grunt.initConfig(&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Project metadata</span></span><br><span class="line">    pkg   : grunt.file.readJSON(<span class="string">'package.json'</span>),</span><br><span class="line">    site  : grunt.file.readYAML(<span class="string">'_config.yml'</span>),</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Before generating any new files, remove files from previous build.</span></span><br><span class="line">    clean: &#123;</span><br><span class="line">      example: [<span class="string">'&lt;%= site.dest %&gt;/*'</span>]</span><br><span class="line">    &#125;,</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Build output from templates and data</span></span><br><span class="line">    assemble: &#123;</span><br><span class="line">      options: &#123;</span><br><span class="line">        flatten: <span class="literal">true</span>,</span><br><span class="line">        production: <span class="literal">false</span>,</span><br><span class="line">        assets: <span class="string">'&lt;%= site.assets %&gt;'</span>,</span><br><span class="line"></span><br><span class="line">        <span class="comment">// Metadata</span></span><br><span class="line">        pkg: <span class="string">'&lt;%= pkg %&gt;'</span>,</span><br><span class="line">        site: <span class="string">'&lt;%= site %&gt;'</span>,</span><br><span class="line">        data: [<span class="string">'&lt;%= site.data %&gt;'</span>],</span><br><span class="line"></span><br><span class="line">        <span class="comment">// Templates</span></span><br><span class="line">        partials: <span class="string">'&lt;%= site.includes %&gt;'</span>,</span><br><span class="line">        layoutdir: <span class="string">'&lt;%= site.layouts %&gt;'</span>,</span><br><span class="line">        layout: <span class="string">'&lt;%= site.layout %&gt;'</span>,</span><br><span class="line"></span><br><span class="line">        <span class="comment">// Extensions</span></span><br><span class="line">        helpers: <span class="string">'&lt;%= site.helpers %&gt;'</span></span><br><span class="line">      &#125;,</span><br><span class="line">      example: &#123;</span><br><span class="line">        files: &#123;</span><br><span class="line">          <span class="string">'&lt;%= site.dest %&gt;'</span>: [<span class="string">'&lt;%= site.templates %&gt;/example.hbs'</span>]</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;);</span><br><span class="line"></span><br><span class="line">  grunt.loadNpmTasks(<span class="string">'grunt-contrib-clean'</span>);</span><br><span class="line">  grunt.loadNpmTasks(<span class="string">'assemble'</span>);</span><br><span class="line"></span><br><span class="line">  grunt.registerTask(<span class="string">'default'</span>, [<span class="string">'clean'</span>, <span class="string">'assemble'</span>]);</span><br><span class="line"></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure></p><p>As you can see, we’re freely making use of the <em>site</em> and <em>pkg</em> variables in both _config.yml and Gruntfile.js, accessing them within <a href="https://lodash.com/" title="Lo-Dash" target="_blank" rel="external">Lo-Dash</a> / <a href="http://underscorejs.org/" title="Underscore" target="_blank" rel="external">Underscore</a> templating.</p><h2 id="Layouts-and-Partials"><a href="#Layouts-and-Partials" class="headerlink" title="Layouts and Partials"></a>Layouts and Partials</h2><p>Next we’ll create the <em>layoutdir</em> and <em>partials</em> directories which will house our <a href="http://assemble.io/docs/Layouts.html" target="_blank" rel="external">layouts</a> and <a href="http://assemble.io/docs/Partials.html" target="_blank" rel="external">partials</a> respectively. A layout is a full page with placeholders to fill in. Partials are re-usable parts of pages which can be included within other pages.</p><p>The <a href="http://assemble.io/docs/" target="_blank" rel="external">Assemble</a> documentation lists both <em>layouts</em> and <em>partials</em>, along with some other concepts, under the “Templates” heading. From this we can assume that all these parts of Assemble can be grouped under the term “Template”. Hence, our directory structure will reflect this (plus I’m just copying the grunt-init-assemble project again):</p><ol><li><code>mkdir -p templates/layouts templates/includes</code></li><li><p><code>vim templates/layouts/default.hbs</code></p> <figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&#123;&#123;&gt; preamble&#125;&#125;</span><br><span class="line"><span class="header">### Begin</span></span><br><span class="line">&#123;&#123;&gt; body &#125;&#125;</span><br><span class="line"><span class="header">### End</span></span><br></pre></td></tr></table></figure></li><li><p><code>vim templates/includes/preamble.hbs</code></p> <figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&#123;&#123;filename&#125;&#125; is just an example.</span><br><span class="line"></span><br><span class="line"><span class="horizontal_rule">---</span></span><br></pre></td></tr></table></figure></li></ol>As you might have guessed, <code>{{> preamble}}</code> and <code>{{> body}}</code> are placeholders which will get filled in with contents from other files, as we'll see later on. <code>{{filename}}</code> is a variable which will resolve to the name of the file being generated.<h2 id="The-example-hbs-page"><a href="#The-example-hbs-page" class="headerlink" title="The example.hbs page"></a>The example.hbs page</h2><p>Lets now fill in another missing piece from our Grunt configuration, the <em>example.hbs</em> file. Note the <em>example</em> target in the <em>assemble</em> <a href="http://gruntjs.com/creating-tasks" target="_blank" rel="external">multi task</a>. In the <em>example</em> target we are specifying that we want a file to be generated from <code>[&#39;&lt;%= site.templates %&gt;/example.hbs&#39;]</code> i.e. from <em>templates/example.hbs</em>.  Of course, we could have added more input files in the array and/or made use of <a href="http://gruntjs.com/configuring-tasks#globbing-patterns" target="_blank" rel="external">globbing patterns</a> to match multiple files - but lets keep things simple.</p><ol><li><code>echo &quot;testing testing&quot; &gt; templates/example.hbs</code></li><li><code>grunt</code><ul><li>Note, you will need to install <em>grunt-cli</em> globally if you don’t already have it: <code>npm i -g grunt-cli</code></li></ul></li></ol><p>Assuming the directory <em>public</em> does not already exist, the file <em>public.html</em> is created. If the <em>public</em> directory exists when you run the Assemble build, then <em>public/example.html</em> is created. I find this a bit confusing so I prefer to explicitly name the generated file in the <em>assemble.example</em> target like so:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// ...</span></span><br><span class="line">      example: &#123;</span><br><span class="line">        files: &#123;</span><br><span class="line">          <span class="string">'&lt;%= site.dest %&gt;/example'</span>: [<span class="string">'&lt;%= site.templates %&gt;/example.hbs'</span>]</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br></pre></td></tr></table></figure><p>I exclude the file extension because it is not picked up from here. The <em>ext</em> option is used for this. <em>assemble.options</em> configures the global settings for the <em>assemble</em> target. These are settings which will apply to all targets in this task unless the task itself overwrites certain settings, like so:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// ...</span></span><br><span class="line">      example: &#123;</span><br><span class="line">        options: &#123;</span><br><span class="line">          ext: <span class="string">'.md'</span></span><br><span class="line">        &#125;,</span><br><span class="line">        files: &#123;</span><br><span class="line">          <span class="string">'&lt;%= site.dest %&gt;/example'</span>: [<span class="string">'&lt;%= site.templates %&gt;/example.hbs'</span>]</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br></pre></td></tr></table></figure><p>Up until now, because we weren’t specifying the ‘ext’ option globally, the default <em>‘.html’</em> has always been applied. However, since we’re now overwritting this option at the target level, running <code>grunt</code> gives us <em>public/example.md</em> with the contents shown below: </p><figure class="highlight md"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">example.md is just an example.</span><br><span class="line"></span><br><span class="line"><span class="horizontal_rule">---</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="header">### Begin</span></span><br><span class="line">testing testing</span><br><span class="line"></span><br><span class="line"><span class="header">### End</span></span><br></pre></td></tr></table></figure><code>{{> preamble}}</code> in default.hbs was substituted with the contents of the preamble.hbs partial and <code>{{> body}}</code> was substituted with the contents of example.hbs, the page that was rendered using the default.hbs layout. <br>Also, there's a small example of using <a href="http://assemble.io/docs/Built-in-Variables.html" target="_blank" rel="external">variables</a> in the preamble partial i.e. <code>{{filename}}</code> which resolves to example.md, the name of the file being generated.<h2 id="Spicing-up-example-hbs"><a href="#Spicing-up-example-hbs" class="headerlink" title="Spicing up example.hbs"></a>Spicing up example.hbs</h2><p>Finally, lets change example.hbs and make it slightly more interesting:</p><p><code>vim templates/example.hbs</code></p><figure class="highlight crystal"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">---</span><br><span class="line"><span class="symbol">title:</span> <span class="constant">Example</span></span><br><span class="line"><span class="symbol">content:</span> [<span class="string">'content/todo-today.md'</span>, <span class="string">'content/todo-tomorrow.md'</span>]</span><br><span class="line">---</span><br><span class="line"></span><br><span class="line"><span class="comment">### &#123;&#123;title&#125;&#125;</span></span><br><span class="line"></span><br><span class="line"><span class="expansion">&#123;&#123;site.description&#125;&#125;</span></span><br><span class="line"><span class="expansion">&#123;&#123;<span class="comment">#each content&#125;&#125;</span></span><br><span class="line">&#123;&#123;str this&#125;&#125;</span></span><br><span class="line"><span class="expansion">&#123;&#123;/each&#125;&#125;</span></span><br></pre></td></tr></table></figure><p>The file starts out by defining two variables, <em>title</em> and <em>content</em>, in the <a href="http://assemble.io/docs/YAML-front-matter.html" title="YAML front matter" target="_blank" rel="external">YAML front matter</a>. Both these variables, as well as the <em>site</em> variable defined in our Gruntfile, are used in the page. You will want to make sure your package.json has a value for the <em>description</em> key if you want anything to show up for <code>{{site.description}}</code>. In my case, I have: </p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">"description": "This is a dummy project meant to explore Assemble."</span><br></pre></td></tr></table></figure><p>The <em>content</em> variable is being used in a <a href="http://handlebarsjs.com/block_helpers.html" title="Handlebars block helper" target="_blank" rel="external">Handlebars block helper</a> to iterate over its values. <code>{{str}}</code> is a <a href="http://assemble.io/docs/Custom-Helpers.html" title="custom helper" target="_blank" rel="external">custom helper</a> which just reads the contents of the file whose path is in <em>this</em> and includes it in the page being built:</p><p><code>vim templates/helpers/str.js</code><br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> fs = <span class="built_in">require</span>(<span class="string">'fs'</span>);</span><br><span class="line"></span><br><span class="line"><span class="built_in">module</span>.exports.register = <span class="function"><span class="keyword">function</span> (<span class="params">Handlebars, options, params</span>) </span>&#123;</span><br><span class="line"><span class="pi">  'use strict'</span>;</span><br><span class="line"></span><br><span class="line">  Handlebars.registerHelper(<span class="string">'str'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">filePath</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> res = fs.readFileSync(filePath, <span class="string">'utf8'</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> Handlebars.SafeString(res);</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure></p><p>Most likely, there is already a helper which does this for us. I have not yet been through the helpers in the <a href="https://github.com/assemble/handlebars-helpers" title="handlebars-helpers" target="_blank" rel="external">handlebars-helpers</a> project. I figured it was just as well to do this “by hand” so to speak, to at least get some experience doing it and demoing it here.</p><p>After filling in our two content files, we can kick off the build process again and get some more interesting results:</p><p><code>vim content/todo-today.md</code><br><figure class="highlight md"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="bullet">* </span>Finish documenting Assemble findings in blog post</span><br><span class="line"><span class="bullet">* </span>Answer emails</span><br></pre></td></tr></table></figure></p><p><code>vim content/todo-tomorrow.md</code><br><figure class="highlight md"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="bullet">* </span>Spend 30 mins on X</span><br><span class="line"><span class="bullet">* </span>Review this week's progress on Y</span><br></pre></td></tr></table></figure></p><p><code>grunt &amp;&amp; cat public/example.md</code><br><figure class="highlight md"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">example.md is just an example.</span><br><span class="line"></span><br><span class="line"><span class="horizontal_rule">---</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="header">### Begin</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="header">### Example</span></span><br><span class="line"></span><br><span class="line">This is a dummy project meant to explore Assemble.</span><br><span class="line"></span><br><span class="line"><span class="bullet">* </span>Finish documenting Assemble findings in blog post</span><br><span class="line"><span class="bullet">* </span>Answer emails</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="bullet">* </span>Spend 30 mins on X</span><br><span class="line"><span class="bullet">* </span>Review this week's progress on Y</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="header">### End</span></span><br></pre></td></tr></table></figure></p><p>A bit more whitespace than I would have liked, but given how customizable all this seems to be, something can most likely be done about that (or maybe pass the output through some kind of postprocessing).</p><p>If you’ve used Assemble before and know how this can be improved (in general, but specifically the <code>{{str}}</code> and whitespace parts), please leave a comment below. I will update and give attribution. Thanks!</p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;Version of Assemble at time of writing: 0.4.42&lt;/p&gt;
&lt;p&gt;If you want to follow along with the end result at hand, the repo is up on &lt;a href=
      
    
    </summary>
    
      <category term="programming" scheme="http://justincalleja.com/categories/programming/"/>
    
    
      <category term="assemble" scheme="http://justincalleja.com/tags/assemble/"/>
    
      <category term="grunt" scheme="http://justincalleja.com/tags/grunt/"/>
    
      <category term="node" scheme="http://justincalleja.com/tags/node/"/>
    
  </entry>
  
  <entry>
    <title>Setting up Karma with Mocha, Chai, and RequireJS</title>
    <link href="http://justincalleja.com/2014/12/26/setting-up-karma-with-mocha-chai-and-requirejs/"/>
    <id>http://justincalleja.com/2014/12/26/setting-up-karma-with-mocha-chai-and-requirejs/</id>
    <published>2014-12-26T00:00:00.000Z</published>
    <updated>2020-04-07T09:25:01.201Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Following-along"><a href="#Following-along" class="headerlink" title="Following along"></a>Following along</h1><p>If you want to follow along with the end result at hand, the repo is up on <a href="https://github.com/justin-calleja/setting-up-karma-with-mocha-chai-requirejs" title="setting-up-karma-with-mocha-chai-requirejs" target="_blank" rel="external">Github</a>. You will need to install dependencies with <code>npm install &amp;&amp; bower install</code></p><table><thead><tr><th style="text-align:left"></th><th style="text-align:center">Versions</th><th style="text-align:right"></th></tr></thead><tbody><tr><td style="text-align:left">Karma</td><td style="text-align:center"></td><td style="text-align:right">0.12.28</td></tr><tr><td style="text-align:left">Node</td><td style="text-align:center"></td><td style="text-align:right">0.10.33</td></tr><tr><td style="text-align:left">NPM</td><td style="text-align:center"></td><td style="text-align:right">1.4.28</td></tr><tr><td style="text-align:left">Bower</td><td style="text-align:center"></td><td style="text-align:right">1.3.12</td></tr></tbody></table><h1 id="Purpose"><a href="#Purpose" class="headerlink" title="Purpose"></a>Purpose</h1><p>Going from zero to a project which supports running <a href="http://mochajs.org/" title="Mocha" target="_blank" rel="external">Mocha</a>/<a href="http://chaijs.com/" title="Chai" target="_blank" rel="external">Chai</a> tests on a browser through <a href="http://karma-runner.github.io/0.12/index.html" title="Karma" target="_blank" rel="external">Karma</a>, with modularity concerns handled by <a href="http://requirejs.org/" title="RequireJS" target="_blank" rel="external">RequireJS</a>.</p><h1 id="Other-resources"><a href="#Other-resources" class="headerlink" title="Other resources"></a>Other resources</h1><ul><li><a href="http://karma-runner.github.io/0.12/plus/requirejs.html" target="_blank" rel="external">http://karma-runner.github.io/0.12/plus/requirejs.html</a> and accompanying repo <a href="https://github.com/kjbekkelund/karma-requirejs" target="_blank" rel="external">https://github.com/kjbekkelund/karma-requirejs</a><ul><li>Great resources to start off with. It’s using Jasmine though. I’d like to set this up with Mocha/Chai so it’s not exactly what I’m looking for. I still borrow heavily from these two resources here.</li></ul></li><li><a href="http://attackofzach.com/setting-up-a-project-using-karma-with-mocha-and-chai/" target="_blank" rel="external">http://attackofzach.com/setting-up-a-project-using-karma-with-mocha-and-chai/</a><ul><li>This one is interesting and it works (I don’t remember if I had to change anything but if I did - nothing major). The only point where it fell short for me was that I needed to have RequireJS in the mix.</li></ul></li><li><p><a href="https://github.com/x2es/boilerplate-karma-mocha-chai-requirejs.git" target="_blank" rel="external">https://github.com/x2es/boilerplate-karma-mocha-chai-requirejs.git</a></p><ul><li><p>This seemed really promising at first, but I’ve had no luck getting it to work. After <code>npm install</code> and <code>karma start</code> I get:</p><blockquote><p>/Users/justin/tmp/boilerplate-karma-mocha-chai-requirejs/node_modules/karma/node_modules/di/lib/injector.js:9</p><p>throw error(‘No provider for “‘ + name + ‘“!’);</p></blockquote><p>Then I figure out it’s missing some dependencies (maybe it was made to work against an older version of Karma even though it’s set to ‘latest’ in package.json). So I <code>npm i --save-dev karma-requirejs karma-chai karma-chrome-launcher</code> to see what happens when the missing dependencies are installed, but running Karma again gives me:</p><blockquote><p>Chrome 39.0.2171 (Mac OS X 10.10.1) ERROR</p><p>Uncaught Error: Mismatched anonymous define() module: function () {</p><p>return (root.sinon = factory());</p><p>}</p><p><a href="http://requirejs.org/docs/errors.html#mismatch" target="_blank" rel="external">http://requirejs.org/docs/errors.html#mismatch</a></p><p>at /Users/justin/tmp/boilerplate-karma-mocha-chai-requirejs/node_modules/requirejs/require.js:141</p><p>ERROR [karma]: [TypeError: Cannot set property ‘results’ of undefined]</p></blockquote><p>At this point I decided it would be better to try set this up from scratch. I’d still have to do this to better understand what’s going on.</p></li></ul></li></ul><h1 id="Setting-up-Karma"><a href="#Setting-up-Karma" class="headerlink" title="Setting up Karma"></a>Setting up Karma</h1><p>Install karma-cli globally if you don’t already have it <code>npm i -g karma-cli</code>. This will allow us to use <code>karma</code> from our projects which have karma installed locally (i.e. instead of <code>./node_modules/karma/bin/karma</code>). Then set up the project:</p><ol><li><code>npm init</code></li><li><code>npm i --save-dev karma</code></li><li><p><code>karma init</code></p><blockquote><p>Which testing framework do you want to use ?<br>Press tab to list possible options. Enter to move to the next question.</p></blockquote><blockquote><p>> <strong>mocha</strong></p></blockquote><blockquote><p>Do you want to use Require.js ?<br>This will add Require.js plugin.<br>Press tab to list possible options. Enter to move to the next question.</p></blockquote><blockquote><p>> <strong>yes</strong></p><p>Do you want to capture any browsers automatically ?<br>Press tab to list possible options. Enter empty string to move to the next question.</p></blockquote><blockquote><p>> <strong>Chrome</strong></p></blockquote><blockquote><p>></p></blockquote><blockquote><p>What is the location of your source and test files ?<br>You can use glob patterns, eg. “js/*.js” or “test/**/*Spec.js”.<br>Enter empty string to move to the next question.</p></blockquote><blockquote><p>> <strong>src/**/*.js</strong></p></blockquote><blockquote><p>> <strong>test/**/*Spec.js</strong></p></blockquote><blockquote><p>> <strong>lib/**/*.js</strong></p></blockquote><blockquote><p>></p></blockquote><blockquote><p>Should any of the files included by the previous patterns be excluded ?<br> You can use glob patterns, eg. “**/*.swp”.<br> Enter empty string to move to the next question.</p></blockquote><blockquote><p><strong>src/main.js</strong></p></blockquote><blockquote><p>></p></blockquote><blockquote><p>Do you wanna generate a bootstrap file for RequireJS?<br> This will generate test-main.js/coffee that configures RequireJS and starts the tests.</p></blockquote><blockquote><p>> <strong>yes</strong></p></blockquote><blockquote><p>Do you want Karma to watch all the files and run the tests on change ?<br> Press tab to list possible options.</p></blockquote><blockquote><p>> <strong>yes</strong></p></blockquote><p> Ignore any warning messages related to patterns not matching any files (they won’t since we don’t have them yet).</p></li></ol><p>This will bring in the Node dependencies we need as well as set us up with a <em>karma.conf.js</em> and <em>test-main.js</em> file.</p><h2 id="karma-conf-js"><a href="#karma-conf-js" class="headerlink" title="karma.conf.js"></a>karma.conf.js</h2><p>This file contains our Karma configuration as per the <code>karma init</code> choices we made. Note the <strong>files</strong> key which lists the files which are loaded by the Karma server (some are included in the browser, some are not depending on the ‘included’ key shown in the snippet below). ‘test-main.js’ has the default included value of true while the files matched by the other three patterns are <strong>not</strong> included in the browser using script tags (they are watched for changes though and can be served from the Karma server (e.g. by requiring them via RequireJS)). You can read up more on this part of the config file <a href="http://karma-runner.github.io/0.12/config/files.html" target="_blank" rel="external">here</a>. I’d rather have ‘test-main.js’ in the ‘test’ directory though, so lets move it and mirror the change in the config:</p><ol><li><code>mkdir test</code></li><li><code>mv test-main.js test/test-main.js</code></li><li><p><code>vim karma.conf.js</code></p> <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">files: [</span><br><span class="line">  <span class="string">'test/test-main.js'</span>,</span><br><span class="line">  &#123;pattern: <span class="string">'src/**/*.js'</span>, included: <span class="literal">false</span>&#125;,</span><br><span class="line">  &#123;pattern: <span class="string">'test/**/*Spec.js'</span>, included: <span class="literal">false</span>&#125;,</span><br><span class="line">  <span class="comment">// include lib/**/*.js otherwise trying to load jquery etc.. from test's RequireJS will fail</span></span><br><span class="line">  &#123;pattern: <span class="string">'lib/**/*.js'</span>, included: <span class="literal">false</span>&#125;</span><br><span class="line">],</span><br></pre></td></tr></table></figure></li></ol><p>Also note that we’re excluding ‘src/main.js’, the file that will contain our RequireJS configuration for when we’ll be bringing in our dependencies from our app’s HTML file. For the purposes of testing, that configuration will be done in ‘test/test-main.js’ instead.</p><h2 id="test-main-js"><a href="#test-main-js" class="headerlink" title="test-main.js"></a>test-main.js</h2><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> allTestFiles = [];</span><br><span class="line"><span class="keyword">var</span> TEST_REGEXP = <span class="regexp">/(spec|test)\.js$/i</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> pathToModule = <span class="function"><span class="keyword">function</span>(<span class="params">path</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> path.replace(<span class="regexp">/^\/base\//</span>, <span class="string">''</span>).replace(<span class="regexp">/\.js$/</span>, <span class="string">''</span>);</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="built_in">Object</span>.keys(<span class="built_in">window</span>.__karma__.files).forEach(<span class="function"><span class="keyword">function</span>(<span class="params">file</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (TEST_REGEXP.test(file)) &#123;</span><br><span class="line">    <span class="comment">// Normalize paths to RequireJS module names.</span></span><br><span class="line">    allTestFiles.push(pathToModule(file));</span><br><span class="line">  &#125;</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="built_in">require</span>.config(&#123;</span><br><span class="line">  <span class="comment">// Karma serves files under /base, which is the basePath from your config file</span></span><br><span class="line">  <span class="comment">// Look at your browser's debugging console if you have trouble loading in files via RequireJS</span></span><br><span class="line">  <span class="comment">// (in our case, we are starting Chrome from Karma).</span></span><br><span class="line">  baseUrl: <span class="string">'/base'</span>,</span><br><span class="line"></span><br><span class="line">  <span class="comment">// dynamically load all test files</span></span><br><span class="line">  deps: allTestFiles,</span><br><span class="line"></span><br><span class="line">  <span class="comment">// The tests are loaded in asynchronously via RequireJS </span></span><br><span class="line">  <span class="comment">// so we need to indicate which function to run to kick things off once they have been loaded.</span></span><br><span class="line">  <span class="comment">// i.e. if you don't include this callback, the tests will not run</span></span><br><span class="line">  <span class="comment">// In our case, Mocha will be running the tests and the karma-mocha adapter has mapped the function to</span></span><br><span class="line">  <span class="comment">// kick things off to window.__karma__.start</span></span><br><span class="line">  callback: <span class="built_in">window</span>.__karma__.start</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>The dependencies (i.e. the tests we want to run) are evaluated dynamically from the files we specified for inclusion in our karma.conf.js file. More specifically, we are filtering out from these files those which match the TEST_REGEXP expression (i.e. any files which end with ‘spec.js’ or ‘test.js’ irrespective of this suffix’s case). The final part of this dependency evaluation is noramlizing the file path to be a correct RequireJS module name by taking off the ‘/base/‘ prefix and ‘.js’ suffix.</p><p>After these dependencies are loaded, we are executing the ‘window.__karma__.start’ function to run our tests as specified in the <a href="http://requirejs.org/docs/api.html#config-callback" target="_blank" rel="external">callback</a> key.</p><h1 id="Setting-up-front-end-dependencies"><a href="#Setting-up-front-end-dependencies" class="headerlink" title="Setting up front-end dependencies"></a>Setting up front-end dependencies</h1><p>Now that Karma’s in place, we’ll want to start pulling in our front-end dependencies. I’ll be using Bower to do that, changing the directory in which Bower installs dependencies to ‘lib’:</p><ol><li>Install Bower globally if you don’t already have it (you’ll probably be using this in many projects so it’s best to have it globally installed anyway): <code>npm install -g bower</code></li><li><code>bower init</code></li><li><p><code>vim .bowerrc</code></p> <figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">    "<span class="attribute">directory</span>": <span class="value"><span class="string">"lib"</span></span><br><span class="line"></span>&#125;</span><br></pre></td></tr></table></figure></li><li><p><code>bower i --save-dev jquery lodash requirejs</code></p><ul><li>This will create the directory ‘lib’ if necessary</li><li>Note: the ‘requirejs’ we’re pulling in here is not the one which will be used in our Karma tests.</li></ul></li></ol><p>You should now have some front-end packages in your lib directory and the appropriate changes in bower.json.</p><p>Also, maybe this is worth addressing. As noted above, the RequireJS we’re pulling in for our front-end app is not the same RequireJS we’re running in our Karma test. When we’ll actually be taking Karma for a spin, you’ll be able to inspect your browser’s console and see that it’s loading the RequireJS in our node_modules. This is set up via the karma-requirejs plugin we’re referring to in our <strong>frameworks</strong> key in karma.conf.js.</p><p>So basically, the RequireJS we’re pulling in via Bower is the one we’ll be making use of from our index.html.</p><h1 id="Dummy-test"><a href="#Dummy-test" class="headerlink" title="Dummy test"></a>Dummy test</h1><p>For the sake of having something to run, I will bring in some code from this repo: <a href="https://github.com/kjbekkelund/karma-requirejs" target="_blank" rel="external">https://github.com/kjbekkelund/karma-requirejs</a></p><p>I’d like to work with Mocha/Chai though, so I’ll be making some changes.</p><p>Lets start with <a href="https://github.com/kjbekkelund/karma-requirejs/blob/master/src/app.js" target="_blank" rel="external">src/app.js</a> (also shown below):</p><ol><li><code>mkdir src</code></li><li><p><code>vim src/app.js</code></p> <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">define(<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> App = <span class="function"><span class="keyword">function</span>(<span class="params">el</span>) </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.el = el;</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    App.prototype.render = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.el.html(<span class="string">'require.js up and running'</span>);</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> App;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure></li></ol><p>Next up, we’ll add <a href="https://github.com/kjbekkelund/karma-requirejs/blob/master/test/appSpec.js" target="_blank" rel="external">test/appSpec.js</a>, with some changes to use Chai’s syntax instead of Jasmine’s (and requiring Lo-Dash instead of Underscore):</p><ul><li><p><code>vim src/appSpec.js</code></p>  <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">define([<span class="string">'app'</span>, <span class="string">'jquery'</span>, <span class="string">'lodash'</span>], <span class="function"><span class="keyword">function</span>(<span class="params">App, $, _</span>) </span>&#123;</span><br><span class="line">  describe(<span class="string">'just checking'</span>, <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line"></span><br><span class="line">    it(<span class="string">'works for app'</span>, <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">      <span class="keyword">var</span> el = $(<span class="string">'&lt;div&gt;&lt;/div&gt;'</span>);</span><br><span class="line"></span><br><span class="line">      <span class="keyword">var</span> app = <span class="keyword">new</span> App(el);</span><br><span class="line">      app.render();</span><br><span class="line"></span><br><span class="line">      expect(el.text()).to.equal(<span class="string">'require.js up and running'</span>);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    it(<span class="string">'works for lodash'</span>, <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">      expect(_.size([<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>])).to.equal(<span class="number">3</span>);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">  &#125;);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure></li></ul><p>Note that we are accessing ‘describe’ and ‘expect’ globally since they’ve been bound to the ‘window’ in their respective Karma plugin files. Our modules and dependencies, though, are pulled in via RequireJS.</p><h1 id="Bringing-in-Chai-a-caveat-and-the-bacon"><a href="#Bringing-in-Chai-a-caveat-and-the-bacon" class="headerlink" title="Bringing in Chai, a caveat, and the bacon"></a>Bringing in Chai, a caveat, and the bacon</h1><p>So now we’re just one step away from running our tests on Karma with this set-up. We still haven’t installed Chai and set it up in our Karma config, so go ahead and do that now:</p><ol><li><code>npm i --save-dev karma-chai chai</code></li><li><p><code>vim karma.conf.js</code></p> <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">frameworks: [<span class="string">'mocha'</span>, <span class="string">'requirejs'</span>, <span class="string">'chai'</span>],</span><br></pre></td></tr></table></figure></li></ol><p><strong>Note:</strong> the order you list the plugins is important. Put ‘chai’ after ‘requirejs’. When I switch these around (as I had done originally), I get:</p><blockquote><p>Uncaught TypeError: Cannot read property ‘should’ of undefined</p></blockquote><blockquote><p>  at /Users/justin/tmp/setting-up-karma/node_modules/karma-chai/adapter.js:4</p></blockquote><p>I found this out thanks to: <a href="https://github.com/xdissent/karma-chai/issues/5" target="_blank" rel="external">https://github.com/xdissent/karma-chai/issues/5</a></p><p>Anyway, although it took longer than I would have liked (missing the ‘lib/**/*.js’ loading in karma.conf.js tripped me up quite a bit), we can kick off Karma with <code>karma start</code> and leave it running while we develop our tests and have them executed in real, possibly multiple, browsers.</p><p>The repo for this example is up on <a href="https://github.com/justin-calleja/setting-up-karma-with-mocha-chai-requirejs" title="setting-up-karma-with-mocha-chai-requirejs" target="_blank" rel="external">Github</a> - remember to get the dependencies: <code>npm install &amp;&amp; bower install</code>. I have added the following two files to this repo which we haven’t talked about yet. Again they are based off of the ones in the <a href="https://github.com/kjbekkelund/karma-requirejs" title="karma-requirejs" target="_blank" rel="external">karma-requirejs</a> example but adapted a bit for this example:</p><ul><li><p><code>vim index.html</code></p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="doctype">&lt;!DOCTYPE html&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="title">html</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="title">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">meta</span> <span class="attribute">charset</span>=<span class="value">"utf-8"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">title</span>&gt;</span>Karma example setup with Require.js<span class="tag">&lt;/<span class="title">title</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">script</span> <span class="attribute">data-main</span>=<span class="value">"src/main.js"</span> <span class="attribute">src</span>=<span class="value">"lib/requirejs/require.js"</span>&gt;</span><span class="undefined"></span><span class="tag">&lt;/<span class="title">script</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="title">head</span>&gt;</span></span><br><span class="line"></span><br><span class="line">  <span class="tag">&lt;<span class="title">body</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="title">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">html</span>&gt;</span></span><br></pre></td></tr></table></figure></li><li><p><code>vim src/main.js</code></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">requirejs.config(&#123;</span><br><span class="line">    paths: &#123;</span><br><span class="line">        <span class="string">'jquery'</span>: <span class="string">'../lib/jquery/dist/jquery'</span>,</span><br><span class="line">        <span class="string">'lodash'</span>: <span class="string">'../lib/lodash/dist/lodash'</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">define([<span class="string">'app'</span>, <span class="string">'jquery'</span>, <span class="string">'lodash'</span>], <span class="function"><span class="keyword">function</span> (<span class="params">App, $, _</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> app = <span class="keyword">new</span> App($(<span class="string">'body'</span>));</span><br><span class="line">    app.render();</span><br><span class="line">    <span class="built_in">console</span>.log(_.size([<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>]));</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure></li></ul><p>If you open up index.html in a browser you should get the text “require.js up and running” and “3” in the console. This is using the RequireJS we pulled in via Bower.</p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h1 id=&quot;Following-along&quot;&gt;&lt;a href=&quot;#Following-along&quot; class=&quot;headerlink&quot; title=&quot;Following along&quot;&gt;&lt;/a&gt;Following along&lt;/h1&gt;&lt;p&gt;If you want to fol
      
    
    </summary>
    
      <category term="programming" scheme="http://justincalleja.com/categories/programming/"/>
    
    
      <category term="chai" scheme="http://justincalleja.com/tags/chai/"/>
    
      <category term="karma" scheme="http://justincalleja.com/tags/karma/"/>
    
      <category term="mocha" scheme="http://justincalleja.com/tags/mocha/"/>
    
      <category term="node" scheme="http://justincalleja.com/tags/node/"/>
    
      <category term="requirejs" scheme="http://justincalleja.com/tags/requirejs/"/>
    
  </entry>
  
  <entry>
    <title>To mock a Mongoose</title>
    <link href="http://justincalleja.com/2014/12/14/to-mock-a-mongoose/"/>
    <id>http://justincalleja.com/2014/12/14/to-mock-a-mongoose/</id>
    <published>2014-12-14T00:00:00.000Z</published>
    <updated>2020-04-07T09:25:01.201Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Purpose"><a href="#Purpose" class="headerlink" title="Purpose"></a>Purpose</h1><p>Use <a href="https://github.com/learnboost/mongoose" title="Mongoose" target="_blank" rel="external">Mongoose</a> in a test without having to have MongoDB running. Mocking done with <a href="https://github.com/mccormicka/Mockgoose" title="Mockgoose" target="_blank" rel="external">Mockgoose</a>.</p><h1 id="Setting-up"><a href="#Setting-up" class="headerlink" title="Setting up"></a>Setting up</h1><p>Setting up can take a while sometimes so I decided to give a different approach a go this time round. I have created a simple <a href="https://github.com/gruntjs/grunt-init" title="grunt-init" target="_blank" rel="external">grunt-init</a> <a href="https://github.com/justin-calleja/mongoose-blog-template-1" title="mongoose-blog-template-1" target="_blank" rel="external">template</a> which will do most of the grunt work for us (such pun!). Install grunt-init globally with <code>npm i -g grunt-init</code> if you don’t already have it. To use the template, simply clone it into your <em>~/.grunt-init/</em> directory (creating the directory if need be):</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">~$ mkdir .grunt-init &amp;&amp; <span class="built_in">cd</span> .grunt-init</span><br><span class="line">~$ git <span class="built_in">clone</span> https://github.com/justin-calleja/mongoose-blog-template-<span class="number">1</span></span><br></pre></td></tr></table></figure><p>Automation time - simply cd into an empty directory and type the magic words:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">to-mock<span class="operator">-a</span>-mongoose$ grunt-init mongoose-blog-template-<span class="number">1</span></span><br><span class="line">to-mock<span class="operator">-a</span>-mongoose$ npm install</span><br></pre></td></tr></table></figure><h1 id="What-have-we-got-here"><a href="#What-have-we-got-here" class="headerlink" title="What have we got here?"></a>What have we got here?</h1><p>First off, install mocha globally if you don’t already have it: <code>npm i -g mocha</code> and run <code>mocha</code>.</p><p>Open up <em>model/db.js</em>. This is where we’re establishing our db connection (and registering some event handlers). The connection will actually be mocked out in our <em>test/test.js</em>. That’s pretty useful. Now we don’t need MongoDB to be running to make some assertions on our code, code that would normally be interacting with the database.</p><p>To get the mocking done right, make sure you mock Mongoose before setting it up:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> mockgoose = <span class="built_in">require</span>(<span class="string">'mockgoose'</span>);</span><br><span class="line"><span class="keyword">var</span> mongoose = <span class="built_in">require</span>(<span class="string">'mongoose'</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// mock mongoose before requiring the script which establishes the connection (to mock the connection)</span></span><br><span class="line">mockgoose(mongoose);</span><br><span class="line"><span class="built_in">require</span>(<span class="string">'../model/db'</span>);</span><br></pre></td></tr></table></figure><p><em>model/item.js</em> defines the structure (the schema) of an Item document which we’d like to store in our db. We’re also creating a model from our schema. This is basically a constructor we can use to create Item objects which will map to documents in our db. i.e. instances created from our Item model will be important to us if we care about interacting with our db.</p><p><em>test/test.js</em>, after mocking our Mongoose, simply requires and makes use.</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// code abbreviated... see generated test.js</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// get a reference to our Item schema/model</span></span><br><span class="line"><span class="keyword">var</span> item = <span class="built_in">require</span>(<span class="string">'../model/item'</span>);</span><br><span class="line"></span><br><span class="line">beforeEach(<span class="function"><span class="keyword">function</span>(<span class="params">done</span>) </span>&#123;</span><br><span class="line">  mockgoose.reset();</span><br><span class="line">  <span class="comment">// create and insert two dummy docs</span></span><br><span class="line">  item.model.create(&#123; text: <span class="string">'write blog on A'</span> &#125;, &#123; text: <span class="string">'write blog on B'</span> &#125;, <span class="function"><span class="keyword">function</span>(<span class="params">err, blogOnA, blogOnB</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">if</span>(err) &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'Error creating documents in beforeEach: '</span> + error);</span><br><span class="line">      <span class="keyword">throw</span>(err);</span><br><span class="line">    &#125;</span><br><span class="line">    done();</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">describe(<span class="string">'Blah'</span>, <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  describe(<span class="string">'Bleh'</span>, <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    it(<span class="string">'item.model.find() should give 2 documents back'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">done</span>) </span>&#123;</span><br><span class="line">      <span class="keyword">var</span> query = item.model.find();</span><br><span class="line">      query.exec(<span class="function"><span class="keyword">function</span>(<span class="params">err, docs</span>) </span>&#123;</span><br><span class="line">        <span class="comment">// expect to find the documents inserted in beforeEach</span></span><br><span class="line">        expect(docs.length).to.equal(<span class="number">2</span>);</span><br><span class="line">        done();</span><br><span class="line">      &#125;);</span><br><span class="line">    &#125;);</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h1 id=&quot;Purpose&quot;&gt;&lt;a href=&quot;#Purpose&quot; class=&quot;headerlink&quot; title=&quot;Purpose&quot;&gt;&lt;/a&gt;Purpose&lt;/h1&gt;&lt;p&gt;Use &lt;a href=&quot;https://github.com/learnboost/mongoos
      
    
    </summary>
    
      <category term="programming" scheme="http://justincalleja.com/categories/programming/"/>
    
    
      <category term="mockgoose" scheme="http://justincalleja.com/tags/mockgoose/"/>
    
      <category term="mongoose" scheme="http://justincalleja.com/tags/mongoose/"/>
    
      <category term="node" scheme="http://justincalleja.com/tags/node/"/>
    
  </entry>
  
  <entry>
    <title>Taking the Express route out</title>
    <link href="http://justincalleja.com/2014/12/06/taking-the-express-route-out/"/>
    <id>http://justincalleja.com/2014/12/06/taking-the-express-route-out/</id>
    <published>2014-12-06T00:00:00.000Z</published>
    <updated>2020-04-07T09:25:01.201Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Purpose"><a href="#Purpose" class="headerlink" title="Purpose"></a>Purpose</h1><p>Example of how to separate route code in Express.js using <code>npm link</code>.</p><h1 id="Setting-up"><a href="#Setting-up" class="headerlink" title="Setting up"></a>Setting up</h1><p>We can use the express generator to get up and running quickly with Express. Install it with <code>npm install express-generator -g</code> if you don’t already have it:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">tmp$ express todo-server</span><br><span class="line">tmp$ <span class="built_in">cd</span> todo-server</span><br><span class="line">todo-server$ npm install</span><br></pre></td></tr></table></figure><p>It might be worth mentioning that at the time of writing, this installs express at version approx 4.9.0 or <em>~4.9.0</em>.</p><p>At this point we could <code>npm start</code> to start our server. As defined in package.json, we’re basically running <code>node ./bin/www</code>.</p><p>We now want to start working on a separate module which will contain the logic behind the <em>/items</em> route in our application:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">todo-server$ mkdir ../todo-items</span><br><span class="line">todo-server$ <span class="built_in">cd</span> ../todo-items</span><br><span class="line">todo-items$ npm init</span><br><span class="line">todo-items$ npm install --save express</span><br></pre></td></tr></table></figure><h1 id="Writing-some-code"><a href="#Writing-some-code" class="headerlink" title="Writing some code"></a>Writing some code</h1><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">todo-items$ vim index.js</span><br></pre></td></tr></table></figure><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> express = <span class="built_in">require</span>(<span class="string">'express'</span>);</span><br><span class="line"><span class="keyword">var</span> router = express.Router();</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> items = <span class="built_in">require</span>(<span class="string">'./items.json'</span>);</span><br><span class="line"></span><br><span class="line">router.get(<span class="string">'/'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">req, res</span>) </span>&#123;</span><br><span class="line">  res.send(items);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="built_in">module</span>.exports = router;</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">todo-items$ vim items.json</span><br></pre></td></tr></table></figure><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">    "<span class="attribute">task A</span>": <span class="value"><span class="literal">true</span></span>,</span><br><span class="line">    "<span class="attribute">task B</span>": <span class="value"><span class="literal">false</span></span><br><span class="line"></span>&#125;</span><br></pre></td></tr></table></figure><p>We’re just defining a GET on ‘/‘.  This means that, whichever route our <em>todo-items</em> module gets loaded on in <em>todo-server</em>, making a GET request on it will give us back our items.json data.</p><p>That’s great but <em>todo-server</em> doesn’t have <em>todo-items</em> installed so how’s it going to use it? We could publish <em>todo-items</em> on npm or host it in a Git repo on Github for example.</p><p>As you can see, we’re just experimenting with <em>todo-items</em> for now. Maybe later we’ll use a proper database. Maybe we’re not sure which database to go with. Point is, we don’t want to publish or host <em>todo-items</em> as it’s still early days, and besides, it would be better to avoid having to stay re-installing the module for every single change we make.</p><p>Enter <code>npm link</code>:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">todo-items$ npm link</span><br><span class="line">/Users/justin/.nvm/v0.<span class="number">10.33</span>/lib/node_modules/todo-items -&gt; /Users/justin/tmp/todo-items</span><br><span class="line"></span><br><span class="line">todo-items$ <span class="built_in">cd</span> ../todo-server</span><br><span class="line">todo-server$ npm link todo-items</span><br><span class="line">/Users/justin/tmp/todo-server/node_modules/todo-items -&gt; /Users/justin/.nvm/v0.<span class="number">10.33</span>/lib/node_modules/todo-items -&gt; /Users/justin/tmp/todo-items</span><br></pre></td></tr></table></figure><p>Executing it from <em>todo-items</em> we get a link to this directory from our global node_modules. <code>npm link todo-items</code> in <em>todo-server</em> gets us a link in <em>todo-server</em>‘s node_modules to the link in our global node_modules, effectively linking back to our <em>todo-items</em> directory containing our implementation for that module. </p><p>End result - if you list the contents of <em>todo-server</em>‘s node_modules you’ll see we have our <em>todo-items</em> in there, albeit a link and not an actual directory structure as our other dependencies are installed as. Now, since the <em>todo-items</em> installation in our <em>todo-server</em> is just a link, any updates we make in <em>todo-items</em> will automatically take effect in our <em>todo-server</em> project.</p><h1 id="Seeing-it-work"><a href="#Seeing-it-work" class="headerlink" title="Seeing it work"></a>Seeing it work</h1><p>Simply require and use:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">todo-server$ vim app.js</span><br></pre></td></tr></table></figure><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> items = <span class="built_in">require</span>(<span class="string">'todo-items'</span>);</span><br><span class="line">app.use(<span class="string">'/items'</span>, items);</span><br></pre></td></tr></table></figure><p>Now we can <code>npm start</code>, hit <a href="http://localhost:3000/items" target="_blank" rel="external">http://localhost:3000/items</a> in a browser, and get our items.json back.</p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h1 id=&quot;Purpose&quot;&gt;&lt;a href=&quot;#Purpose&quot; class=&quot;headerlink&quot; title=&quot;Purpose&quot;&gt;&lt;/a&gt;Purpose&lt;/h1&gt;&lt;p&gt;Example of how to separate route code in Express.j
      
    
    </summary>
    
      <category term="programming" scheme="http://justincalleja.com/categories/programming/"/>
    
    
      <category term="express" scheme="http://justincalleja.com/tags/express/"/>
    
      <category term="node" scheme="http://justincalleja.com/tags/node/"/>
    
  </entry>
  
  <entry>
    <title>Using Viper for some Go basics</title>
    <link href="http://justincalleja.com/2014/10/25/using-viper-for-some-go-basics/"/>
    <id>http://justincalleja.com/2014/10/25/using-viper-for-some-go-basics/</id>
    <published>2014-10-25T00:00:00.000Z</published>
    <updated>2020-04-07T09:25:01.205Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Intro"><a href="#Intro" class="headerlink" title="Intro"></a>Intro</h1><p>This post will walk you through the basic usage of <a href="https://github.com/spf13/viper" title="Viper" target="_blank" rel="external">Viper</a>. It is intended for people who are new to the <a href="https://golang.org/" title="Go programming language" target="_blank" rel="external">Go</a> programming language (I am just starting out myself). This is because the purpose isn’t Viper per se, but the process of doing some of the basics in Go.</p><h2 id="Assumptions"><a href="#Assumptions" class="headerlink" title="Assumptions"></a>Assumptions</h2><ul><li>You have Go installed. In my case: <strong>go version go1.3.3 darwin/amd64</strong></li></ul><h1 id="Setting-up"><a href="#Setting-up" class="headerlink" title="Setting up"></a>Setting up</h1><p>First of all, we need to create a directory to house our work i.e. we need to create a workspace:</p><blockquote><p>Go code must be kept inside a workspace. A workspace is a directory hierarchy with three directories at its root:</p><ul><li>src</li><li>pkg</li><li>bin</li></ul><footer><cite><a href="https://golang.org/doc/code.html" target="_blank" rel="external">How to Write Go Code</a></cite></footer></blockquote><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">$ mkdir useviper_workspace</span><br><span class="line"></span><br><span class="line">$ <span class="built_in">cd</span> useviper_workspace</span><br><span class="line"></span><br><span class="line">useviper_workspace$ mkdir src bin pkg</span><br></pre></td></tr></table></figure><p>Next, lets create the directory which will actually house our source code for this post / your project. In doing so, it’s handy to keep the following best practice in mind:</p><blockquote><p>The packages from the standard library are given short paths such as “fmt” and “net/http”. For your own packages, you must choose a base path that is unlikely to collide with future additions to the standard library or other external libraries.</p><p>If you keep your code in a source repository somewhere, then you should use the root of that source repository as your base path. For instance, if you have a GitHub account at github.com/user, that should be your base path.</p><p>Note that you don’t need to publish your code to a remote repository before you can build it. It’s just a good habit to organize your code as if you will publish it someday. In practice you can choose any arbitrary path name, as long as it is unique to the standard library and greater Go ecosystem.</p><footer><cite><a href="https://golang.org/doc/code.html" target="_blank" rel="external">How to Write Go Code</a></cite></footer></blockquote><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">useviper_workspace$ mkdir -p src/github.com/justincalleja/useviper</span><br></pre></td></tr></table></figure><p>I’ll go with <strong>github.com/justincalleja/useviper</strong>. Shortly, we will see that <code>go</code> can be used to fetch 3rd party source code which is publicly hosted and that the directory structure plays a role in this i.e. if you’re planning to push your code to some public repo, you’ll want to reflect that in the directory structure leading to the root of your project’s source code (e.g. <strong>github.com/username/projectname</strong>).</p><p>Before continuing, you’ll want to set your <strong>GOPATH</strong> environment variable:</p><blockquote><p>The GOPATH environment variable specifies the location of your workspace.</p><p>Your workspace can be located wherever you like &hellip; Note that this must not be the same path as your Go installation.</p><footer><cite><a href="https://golang.org/doc/code.html" target="_blank" rel="external">How to Write Go Code</a></cite></footer></blockquote><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">useviper_workspace$ <span class="built_in">echo</span> <span class="variable">$GOPATH</span></span><br><span class="line">/Users/justin/go-stuff/useviper_workspace</span><br><span class="line"></span><br><span class="line">useviper_workspace$ <span class="built_in">type</span> <span class="built_in">set</span>_gopath</span><br><span class="line"><span class="built_in">set</span>_gopath is a <span class="keyword">function</span></span><br><span class="line"><span class="function"><span class="title">set_gopath</span></span> ()</span><br><span class="line">&#123;</span><br><span class="line">    <span class="built_in">export</span> GOPATH=`<span class="built_in">pwd</span>`;</span><br><span class="line">    <span class="built_in">export</span> PATH=<span class="variable">$GOPATH</span>/bin:<span class="variable">$PATH</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>I already have my <strong>GOPATH</strong> set using the <code>set_gopath</code> bash function which is shown above. You can put this in any file which is sourced when you start your terminal (e.g. ~/.bashrc, ~/.profile etc&hellip;).</p><h1 id="Running-some-code"><a href="#Running-some-code" class="headerlink" title="Running some code"></a>Running some code</h1><p>Finally, we can get to writing some code. If you want to, initialize a git repo at <strong>src/github.com/&lt; your-username &gt;/useviper</strong> and go ahead and add <strong>useviper.go</strong> in there:</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line"><span class="string">"fmt"</span></span><br><span class="line"><span class="string">"github.com/spf13/viper"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="keyword">func</span> main() &#123;</span><br><span class="line">fmt.Println(<span class="string">"in main"</span>)</span><br><span class="line">viper.SetConfigName(<span class="string">"config"</span>) <span class="comment">// name of config file (without extension)</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>We’re just printing to standard out and making basic usage of Viper as per <a href="https://github.com/spf13/viper" target="_blank" rel="external">usage instructions</a> (note that if you don’t use something you import the compiler will complain about it and won’t let you build).</p><p>Now “fmt” is built-in, but what about “github.com/spf13/viper”? How do we get that dependency?</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">useviper_workspace$ go get</span><br><span class="line">can<span class="string">'t load package: package .: no buildable Go source files in /Users/justin/go-stuff/useviper_workspace</span></span><br></pre></td></tr></table></figure><p>If I try running <code>go get</code> from the root of my workspace I get the error shown above. It seems that <code>go get</code> is expecting Go lang source files to be in the directory you’re running it in. Try running it again in the <strong>useviper</strong> directory where we have our <strong>useviper.go</strong> file. This time it hangs for a while. That’s because <code>go get</code> is scanning the source files it finds and downloading, building and installing our dependencies and code into our workspace. If we print out the directory structure down to 3 levels we get:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">useviper_workspace$ tree -L <span class="number">3</span></span><br><span class="line">.</span><br><span class="line">├── bin</span><br><span class="line">│   └── useviper</span><br><span class="line">├── pkg</span><br><span class="line">│   └── darwin_amd64</span><br><span class="line">│       ├── github.com</span><br><span class="line">│       └── gopkg.in</span><br><span class="line">└── src</span><br><span class="line">    ├── github.com</span><br><span class="line">    │   ├── BurntSushi</span><br><span class="line">    │   ├── justincalleja</span><br><span class="line">    │   ├── kr</span><br><span class="line">    │   ├── mitchellh</span><br><span class="line">    │   └── spf13</span><br><span class="line">    └── gopkg.in</span><br><span class="line">        └── yaml.v1</span><br></pre></td></tr></table></figure><p>In our case, we didn’t really need <code>go get</code> to stay parsing and figuring out what dependencies our project needs as we have only one (which in turn has it’s own dependencies). We could have achieved the same result by running <code>go get github.com/spf13/viper</code> from the root of our workspace.</p><p>As you can see, our <strong>src</strong>, <strong>pkg</strong>, and <strong>bin</strong> directories have been populated. <strong>src</strong> now includes the source code of our dependencies recursively (Viper is in <strong>github.com/spf13/viper</strong>). <strong>pkg</strong> contains library binaries. These binaries cannot be executed but they can be linked to. <strong>bin</strong> is where executable binaries go. The <strong>main()</strong> function in useviper.go makes the result of building the file an executable binary, so it’s placed in bin and we can run it.</p><p>Since we’ve added <strong>$GOPATH/bin</strong> to our <strong>PATH</strong> environment variable (refer to the <code>set_gopath</code> executable function above), running useviper at the terminal is simply a matter of entering the file’s name: <code>useviper</code>, which gives us back “in main”.</p><p>Next, we want to be able to modify our source code and rebuild. Change your <strong>main()</strong> function to look like the following:</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">func</span> main() &#123;</span><br><span class="line">viper.SetConfigName(<span class="string">"config"</span>) <span class="comment">// name of config file (without extension)</span></span><br><span class="line">viper.AddConfigPath(<span class="string">"."</span>)      <span class="comment">// path to look for the config file in</span></span><br><span class="line"></span><br><span class="line">err := viper.ReadInConfig()</span><br><span class="line"><span class="keyword">if</span> err != <span class="constant">nil</span> &#123;</span><br><span class="line">fmt.Println(<span class="string">"Config not found..."</span>)</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">name := viper.GetString(<span class="string">"name"</span>)</span><br><span class="line">fmt.Println(<span class="string">"Config found, name = "</span>, name)</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>In order to install (build and put in <strong>bin</strong>), we find ourselves in the same sort of situation as we did with <code>go get</code>. We can either rely on being in the directory our source files are in and run <code>go install</code>, or we can specify what to install explicitly. I like having the <strong>goinstall.sh</strong> script around in my workspace root (shown below).</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="shebang">#!/bin/bash</span></span><br><span class="line"><span class="keyword">if</span> [ <span class="variable">$#</span> <span class="operator">-eq</span> <span class="number">0</span> ]</span><br><span class="line"><span class="keyword">then</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">"go install github.com/justincalleja/useviper"</span> &amp;&amp; go install github.com/justincalleja/useviper</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">    <span class="built_in">echo</span> <span class="string">"go install github.com/justincalleja/<span class="variable">$1</span>"</span> &amp;&amp; go install github.com/justincalleja/<span class="variable">$1</span></span><br><span class="line"><span class="keyword">fi</span></span><br></pre></td></tr></table></figure><p>I thought it might be useful to install with just the project name (and a default) from the project root&hellip; but I have yet to develop enough in Go to see what is actually helpful or not in the process of writing code.</p><p>Basically, all the following will install <code>useviper</code> in <strong>bin</strong> for us:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">useviper_workspace$ goinstall.sh</span><br><span class="line"></span><br><span class="line">useviper_workspace$ goinstall.sh useviper</span><br><span class="line"></span><br><span class="line">useviper$ go install</span><br></pre></td></tr></table></figure><p>If you <code>useviper</code> now you should get: “Config not found…”. But if you create a file named <strong>config.yaml</strong> in the directory in which you’re going to run <code>useviper</code> with the following contents:</p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">name: viper</span><br></pre></td></tr></table></figure><p>you should get back “Config found, name =  viper”. Note that we did not need to set the config file’s extension in our <strong>main()</strong> as Viper picks up YAML, TOML, or JSON files automatically.</p><p>That wraps up this quick introduction to some Go lang basics :)</p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h1 id=&quot;Intro&quot;&gt;&lt;a href=&quot;#Intro&quot; class=&quot;headerlink&quot; title=&quot;Intro&quot;&gt;&lt;/a&gt;Intro&lt;/h1&gt;&lt;p&gt;This post will walk you through the basic usage of &lt;a href
      
    
    </summary>
    
      <category term="programming" scheme="http://justincalleja.com/categories/programming/"/>
    
    
      <category term="go" scheme="http://justincalleja.com/tags/go/"/>
    
      <category term="viper" scheme="http://justincalleja.com/tags/viper/"/>
    
  </entry>
  
</feed>
